added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / jscript / engine / convert.cs
blob3a98650c15111126f80f4886f6b505e59e9917bf
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 //
14 // ==--==
16 namespace Microsoft.JScript {
18 using Microsoft.JScript.Vsa;
19 using System;
20 using System.Globalization;
21 using System.Reflection;
22 using System.Reflection.Emit;
23 using System.Security;
24 using System.Text;
25 using System.Runtime.InteropServices;
26 using System.Diagnostics;
28 enum PreferredType : int {Either, Number, String, LocaleString};
30 public sealed class Convert{
32 public static bool IsBadIndex(AST ast){
33 Int32 i;
34 if (!(ast is ConstantWrapper))
35 return false;
36 try{
37 i = (Int32)CoerceT(((ConstantWrapper)ast).value, typeof(System.Int32));
38 }catch{
39 return true;
41 return i < 0;
44 public static Double CheckIfDoubleIsInteger(Double d){
45 if (d == System.Math.Round(d)) return d;
46 throw new JScriptException(JSError.TypeMismatch);
49 public static Single CheckIfSingleIsInteger(Single s){
50 if (s == System.Math.Round(s)) return s;
51 throw new JScriptException(JSError.TypeMismatch);
54 //This routine converts a value to the desired type, if possible.
55 //It throws an exception if the conversion has not been provided for, as well as when loss of information will occur.
56 //For example, coercing 1.5 to type Int32 will throw an exception.
57 public static Object Coerce(Object value, Object type){
58 return Convert.Coerce(value, type, false);
61 internal static Object Coerce(Object value, Object type, bool explicitOK){
62 TypeExpression te = type as TypeExpression;
63 if (te != null)
64 type = te.ToIReflect();
65 TypedArray ta = type as TypedArray;
66 if (ta != null){
67 IReflect eIr = ta.elementType;
68 int rank = ta.rank;
69 Type eTy = eIr is Type ? (Type)eIr : eIr is ClassScope ? ((ClassScope)eIr).GetBakedSuperType() : typeof(Object);
70 ArrayObject ao = value as ArrayObject;
71 if (ao != null)
72 return ao.ToNativeArray(eTy);
73 Array arr = value as Array;
74 if (arr != null && arr.Rank == rank)
75 type = Convert.ToType(TypedArray.ToRankString(rank), eTy);
76 if (value == null || value is DBNull)
77 return null;
79 ClassScope csc = type as ClassScope;
80 if (csc != null){
81 if (csc.HasInstance(value))
82 return value;
83 else{
84 EnumDeclaration ed = csc.owner as EnumDeclaration;
85 if (ed != null){
86 EnumWrapper ew = value as EnumWrapper;
87 if (ew != null)
88 if (ew.classScopeOrType == csc) return value; else throw new JScriptException(JSError.TypeMismatch);
89 return new DeclaredEnumValue(Coerce(value, ed.baseType), null, csc);
91 if (value == null || value is DBNull) return null;
92 throw new JScriptException(JSError.TypeMismatch);
94 }else if (!(type is Type))
95 type = Convert.ToType(Runtime.TypeRefs, (IReflect)type);
96 else if (type == typeof(Type) && value is ClassScope)
97 return value;
98 else if (((Type)type).IsEnum){
99 EnumWrapper ew = value as EnumWrapper;
100 if (ew != null) {
101 if (ew.classScopeOrType == type)
102 return value;
103 else
104 throw new JScriptException(JSError.TypeMismatch);
107 Type t = type as Type;
108 return MetadataEnumValue.GetEnumValue(t, Convert.CoerceT(value, Convert.GetUnderlyingType(t), explicitOK));
110 return Convert.CoerceT(value, (Type)type, explicitOK);
113 //This routine converts a value to the desired type, if possible.
114 //It throws an exception if the conversion has not been provided for, as well as when loss of information will occur.
115 //For example, coercing 1.5 to type Int32 will throw an exception.
116 internal static Object CoerceT(Object value, Type type){
117 return Convert.CoerceT(value, type, false);
120 public static Object CoerceT(Object value, Type t, bool explicitOK) {
121 if (t == typeof(Object)) return value;
122 if (t == typeof(String) && value is String) return value;
123 if (t.IsEnum && !(t is EnumBuilder) && !(t is TypeBuilder)){
124 IConvertible ic = Convert.GetIConvertible(value);
125 TypeCode vc = Convert.GetTypeCode(value, ic);
126 if (vc == TypeCode.String)
127 return Enum.Parse(t, ic.ToString(CultureInfo.InvariantCulture));
128 else{
129 if (!explicitOK && vc != TypeCode.Empty){
130 Type vty = value.GetType();
131 if (vty.IsEnum)
132 if (vty != t) throw new JScriptException(JSError.TypeMismatch); else return value;
134 return Enum.ToObject(t, Convert.CoerceT(value, Convert.GetUnderlyingType(t), explicitOK));
137 TypeCode c2 = Type.GetTypeCode(t);
138 if (c2 != TypeCode.Object)
139 return Convert.Coerce2(value, c2, explicitOK);
140 if (value is ConcatString) value = value.ToString();
141 if (value == null || (value == DBNull.Value && t != typeof(Object)) || value is Missing || value is System.Reflection.Missing)
142 if (t.IsValueType) {
143 // Activator.CreateInstance looks at the immediate caller to check if an internal type can
144 // be created. Only allow public types in this assembly to be created.
145 if (!t.IsPublic && t.Assembly == typeof(ActiveXObjectConstructor).Assembly)
146 throw new JScriptException(JSError.CantCreateObject);
147 return Activator.CreateInstance(t);
149 else
150 return null;
151 else if (t.IsAssignableFrom(value.GetType()))
152 return value;
153 else if (typeof(Delegate).IsAssignableFrom(t)){
154 if (value is Closure)
155 return ((Closure)value).ConvertToDelegate(t);
156 else if (value is FunctionWrapper)
157 return ((FunctionWrapper)value).ConvertToDelegate(t);
158 else if (value is FunctionObject) //called at compile-time from ConstantWrapper
159 return value; //Do nothing, ConstantWrapper will do the right thing.
160 }else if (value is ArrayObject && typeof(Array).IsAssignableFrom(t))
161 return ((ArrayObject)value).ToNativeArray(t.GetElementType());
162 else if (value is Array && t == typeof(ArrayObject) && ((Array)value).Rank == 1){
163 if (Globals.contextEngine == null){
164 Globals.contextEngine = new VsaEngine(true); //ASP+ case
165 Globals.contextEngine.InitVsaEngine("JS7://Microsoft.JScript.Vsa.VsaEngine", new DefaultVsaSite());
167 return Globals.contextEngine.GetOriginalArrayConstructor().ConstructWrapper((Array)value);
168 }else if (value is ClassScope && t == typeof(Type))
169 return ((ClassScope)value).GetTypeBuilderOrEnumBuilder();
170 else if (value is TypedArray && t == typeof(Type))
171 return ((TypedArray)value).ToType();
172 //Look for a suitable op_Implicit or op_Explicit conversion
173 Type source_type = value.GetType();
174 MethodInfo meth = null;
175 if (explicitOK){
176 meth = t.GetMethod("op_Explicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
177 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
178 meth = new JSMethodInfo(meth);
179 return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
181 meth = Convert.GetToXXXXMethod(source_type, t, explicitOK);
182 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
183 meth = new JSMethodInfo(meth);
184 if (meth.IsStatic)
185 return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
186 else
187 return meth.Invoke(value, BindingFlags.SuppressChangeType, null, new Object[]{}, null);
190 meth = t.GetMethod("op_Implicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
191 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
192 meth = new JSMethodInfo(meth);
193 return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
195 meth = Convert.GetToXXXXMethod(source_type, t, false);
196 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
197 meth = new JSMethodInfo(meth);
198 if (meth.IsStatic)
199 return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
200 else
201 return meth.Invoke(value, BindingFlags.SuppressChangeType, null, new Object[]{}, null);
203 if (t.IsByRef)
204 return Convert.CoerceT(value, t.GetElementType());
205 Type vt = value.GetType();
206 throw new JScriptException(JSError.TypeMismatch);
209 //Call this routine only for target TypeTokens other than Object and Empty
210 //It special cases the well known types with JScript specific conversion semantics
211 public static Object Coerce2(Object value, TypeCode target, bool truncationPermitted){
212 if (truncationPermitted) return Coerce2WithTruncationPermitted(value, target);
213 return Coerce2WithNoTrunctation(value, target);
216 private static Object Coerce2WithNoTrunctation(Object value, TypeCode target){
217 if (value is EnumWrapper)
218 value = ((EnumWrapper)value).value;
219 if (value is ConstantWrapper)
220 value = ((ConstantWrapper)value).value;
221 try{ checked{
222 IConvertible ic = Convert.GetIConvertible(value);
223 switch (Convert.GetTypeCode(value, ic)){
224 case TypeCode.Empty:
225 switch (target){
226 case TypeCode.DBNull: return DBNull.Value;
227 case TypeCode.Boolean: return false;
228 case TypeCode.Char: return (Char)0;
229 case TypeCode.SByte: return (SByte)0;
230 case TypeCode.Byte: return (Byte)0;
231 case TypeCode.Int16: return (Int16)0;
232 case TypeCode.UInt16: return (UInt16)0;
233 case TypeCode.Int32: return (Int32)0;
234 case TypeCode.UInt32: return (UInt32)0;
235 case TypeCode.Int64: return (Int64)0;
236 case TypeCode.UInt64: return (UInt64)0;
237 case TypeCode.Single: return Single.NaN;
238 case TypeCode.Double: return Double.NaN;
239 case TypeCode.Decimal: return (Decimal)0;
240 case TypeCode.DateTime: return new DateTime((Int64)0);
241 case TypeCode.String: return null;
243 break;
245 case TypeCode.Object:
246 if (value is System.Reflection.Missing || (value is Missing && target != TypeCode.Object)) goto case TypeCode.Empty;
247 switch (target){
248 case TypeCode.Boolean: return Convert.ToBoolean(value, false);
249 case TypeCode.Char:
250 case TypeCode.SByte:
251 case TypeCode.Byte:
252 case TypeCode.Int16:
253 case TypeCode.UInt16:
254 case TypeCode.Int32:
255 case TypeCode.UInt32:
256 case TypeCode.Int64:
257 case TypeCode.UInt64:
258 case TypeCode.Single:
259 case TypeCode.Double:
260 case TypeCode.Decimal: return Coerce2WithNoTrunctation(Convert.ToNumber(value, ic), target);
261 case TypeCode.DateTime:
262 if (value is DateObject)
263 return DatePrototype.getVarDate((DateObject)value);
264 else
265 return Coerce2WithNoTrunctation(Convert.ToNumber(value, ic), target);
266 case TypeCode.String: return Convert.ToString(value, ic);
268 break;
270 case TypeCode.DBNull:
271 switch (target){
272 case TypeCode.DBNull: return DBNull.Value;
273 case TypeCode.Boolean: return false;
274 case TypeCode.Char: return (Char)0;
275 case TypeCode.SByte: return (SByte)0;
276 case TypeCode.Byte: return (Byte)0;
277 case TypeCode.Int16: return (Int16)0;
278 case TypeCode.UInt16: return (UInt16)0;
279 case TypeCode.Int32: return (Int32)0;
280 case TypeCode.UInt32: return (UInt32)0;
281 case TypeCode.Int64: return (Int64)0;
282 case TypeCode.UInt64: return (UInt64)0;
283 case TypeCode.Single: return (Single)0;
284 case TypeCode.Double: return (Double)0;
285 case TypeCode.Decimal: return (Decimal)0;
286 case TypeCode.DateTime: return new DateTime((Int64)0);
287 case TypeCode.String: return null;
289 break;
291 case TypeCode.Boolean:
292 bool b = ic.ToBoolean(null);
293 int bi = b ? 1 : 0;
294 switch (target){
295 case TypeCode.Boolean: return b;
296 case TypeCode.Char: return (Char)bi;
297 case TypeCode.SByte: return (SByte)bi;
298 case TypeCode.Byte: return (Byte)bi;
299 case TypeCode.Int16: return (Int16)bi;
300 case TypeCode.UInt16: return (UInt16)bi;
301 case TypeCode.Int32: return (Int32)bi;
302 case TypeCode.UInt32: return (UInt32)bi;
303 case TypeCode.Int64: return (Int64)bi;
304 case TypeCode.UInt64: return (UInt64)bi;
305 case TypeCode.Single: return (Single)bi;
306 case TypeCode.Double: return (Double)bi;
307 case TypeCode.Decimal: return (Decimal)bi;
308 case TypeCode.DateTime: return new DateTime((Int64)bi);
309 case TypeCode.String: return b ? "true" : "false";
311 break;
313 case TypeCode.Char:
314 Char ch = ic.ToChar(null);
315 UInt16 us = (UInt16)ch;
316 switch (target){
317 case TypeCode.Boolean: return us != 0;
318 case TypeCode.Char: return ch;
319 case TypeCode.SByte: return (SByte)us;
320 case TypeCode.Byte: return (Byte)us;
321 case TypeCode.Int16: return (Int16)us;
322 case TypeCode.UInt16: return us;
323 case TypeCode.Int32: return (Int32)us;
324 case TypeCode.UInt32: return (UInt32)us;
325 case TypeCode.Int64: return (Int64)us;
326 case TypeCode.UInt64: return (UInt64)us;
327 case TypeCode.Single: return (Single)us;
328 case TypeCode.Double: return (Double)us;
329 case TypeCode.Decimal: return (Decimal)us;
330 case TypeCode.DateTime: return new DateTime((Int64)us);
331 case TypeCode.String: return Char.ToString(ch);
333 break;
335 case TypeCode.SByte:
336 SByte sb = ic.ToSByte(null);
337 switch (target){
338 case TypeCode.Boolean: return sb != 0;
339 case TypeCode.Char: return (Char)sb;
340 case TypeCode.SByte: return sb;
341 case TypeCode.Byte: return (Byte)sb;
342 case TypeCode.Int16: return (Int16)sb;
343 case TypeCode.UInt16: return (UInt16)sb;
344 case TypeCode.Int32: return (Int32)sb;
345 case TypeCode.UInt32: return (UInt32)sb;
346 case TypeCode.Int64: return (Int64)sb;
347 case TypeCode.UInt64: return (UInt64)sb;
348 case TypeCode.Single: return (Single)sb;
349 case TypeCode.Double: return (Double)sb;
350 case TypeCode.Decimal: return (Decimal)sb;
351 case TypeCode.DateTime: return new DateTime((Int64)sb);
352 case TypeCode.String: return sb.ToString(CultureInfo.InvariantCulture);
354 break;
356 case TypeCode.Byte:
357 Byte ub = ic.ToByte(null);
358 switch (target){
359 case TypeCode.Boolean: return ub != 0;
360 case TypeCode.Char: return (Char)ub;
361 case TypeCode.SByte: return (SByte)ub;
362 case TypeCode.Byte: return ub;
363 case TypeCode.Int16: return (Int16)ub;
364 case TypeCode.UInt16: return (UInt16)ub;
365 case TypeCode.Int32: return (Int32)ub;
366 case TypeCode.UInt32: return (UInt32)ub;
367 case TypeCode.Int64: return (Int64)ub;
368 case TypeCode.UInt64: return (UInt64)ub;
369 case TypeCode.Single: return (Single)ub;
370 case TypeCode.Double: return (Double)ub;
371 case TypeCode.Decimal: return (Decimal)ub;
372 case TypeCode.DateTime: return new DateTime((Int64)ub);
373 case TypeCode.String: return ub.ToString(CultureInfo.InvariantCulture);
375 break;
377 case TypeCode.Int16:
378 Int16 s = ic.ToInt16(null);
379 switch (target){
380 case TypeCode.Boolean: return s != 0;
381 case TypeCode.Char: return (Char)s;
382 case TypeCode.SByte: return (SByte)s;
383 case TypeCode.Byte: return (Byte)s;
384 case TypeCode.Int16: return s;
385 case TypeCode.UInt16: return (UInt16)s;
386 case TypeCode.Int32: return (Int32)s;
387 case TypeCode.UInt32: return (UInt32)s;
388 case TypeCode.Int64: return (Int64)s;
389 case TypeCode.UInt64: return (UInt64)s;
390 case TypeCode.Single: return (Single)s;
391 case TypeCode.Double: return (Double)s;
392 case TypeCode.Decimal: return (Decimal)s;
393 case TypeCode.DateTime: return new DateTime((Int64)s);
394 case TypeCode.String: return s.ToString(CultureInfo.InvariantCulture);
396 break;
398 case TypeCode.UInt16:
399 us = ic.ToUInt16(null);
400 switch (target){
401 case TypeCode.Boolean: return us != 0;
402 case TypeCode.Char: return (Char)us;
403 case TypeCode.SByte: return (SByte)us;
404 case TypeCode.Byte: return (Byte)us;
405 case TypeCode.Int16: return (Int16)us;
406 case TypeCode.UInt16: return us;
407 case TypeCode.Int32: return (Int32)us;
408 case TypeCode.UInt32: return (UInt32)us;
409 case TypeCode.Int64: return (Int64)us;
410 case TypeCode.UInt64: return (UInt64)us;
411 case TypeCode.Single: return (Single)us;
412 case TypeCode.Double: return (Double)us;
413 case TypeCode.Decimal: return (Decimal)us;
414 case TypeCode.DateTime: return new DateTime((Int64)us);
415 case TypeCode.String: return us.ToString(CultureInfo.InvariantCulture);
417 break;
419 case TypeCode.Int32:
420 Int32 i = ic.ToInt32(null);
421 switch (target){
422 case TypeCode.Boolean: return i != 0;
423 case TypeCode.Char: return (Char)i;
424 case TypeCode.SByte: return (SByte)i;
425 case TypeCode.Byte: return (Byte)i;
426 case TypeCode.Int16: return (Int16)i;
427 case TypeCode.UInt16: return (UInt16)i;
428 case TypeCode.Int32: return i;
429 case TypeCode.UInt32: return (UInt32)i;
430 case TypeCode.Int64: return (Int64)i;
431 case TypeCode.UInt64: return (UInt64)i;
432 case TypeCode.Single: return (Single)i;
433 case TypeCode.Double: return (Double)i;
434 case TypeCode.Decimal: return (Decimal)i;
435 case TypeCode.DateTime: return new DateTime((Int64)i);
436 case TypeCode.String: return i.ToString(CultureInfo.InvariantCulture);
438 break;
440 case TypeCode.UInt32:
441 UInt32 ui = ic.ToUInt32(null);
442 switch (target){
443 case TypeCode.Boolean: return ui != 0;
444 case TypeCode.Char: return (Char)ui;
445 case TypeCode.SByte: return (SByte)ui;
446 case TypeCode.Byte: return (Byte)ui;
447 case TypeCode.Int16: return (Int16)ui;
448 case TypeCode.UInt16: return (UInt16)ui;
449 case TypeCode.Int32: return (Int32)ui;
450 case TypeCode.UInt32: return ui;
451 case TypeCode.Int64: return (Int64)ui;
452 case TypeCode.UInt64: return (UInt64)ui;
453 case TypeCode.Single: return (Single)ui;
454 case TypeCode.Double: return (Double)ui;
455 case TypeCode.Decimal: return (Decimal)ui;
456 case TypeCode.DateTime: return new DateTime((Int64)ui);
457 case TypeCode.String: return ui.ToString(CultureInfo.InvariantCulture);
459 break;
461 case TypeCode.Int64:
462 Int64 l = ic.ToInt64(null);
463 switch (target){
464 case TypeCode.Boolean: return l != 0;
465 case TypeCode.Char: return (Char)l;
466 case TypeCode.SByte: return (SByte)l;
467 case TypeCode.Byte: return (Byte)l;
468 case TypeCode.Int16: return (Int16)l;
469 case TypeCode.UInt16: return (UInt16)l;
470 case TypeCode.Int32: return (Int32)l;
471 case TypeCode.UInt32: return (UInt32)l;
472 case TypeCode.Int64: return l;
473 case TypeCode.UInt64: return (UInt64)l;
474 case TypeCode.Single: return (Single)l;
475 case TypeCode.Double: return (Double)l;
476 case TypeCode.Decimal: return (Decimal)l;
477 case TypeCode.DateTime: return new DateTime(l);
478 case TypeCode.String: return l.ToString(CultureInfo.InvariantCulture);
480 break;
482 case TypeCode.UInt64:
483 UInt64 ul = ic.ToUInt64(null);
484 switch (target){
485 case TypeCode.Boolean: return ul != 0;
486 case TypeCode.Char: return (Char)ul;
487 case TypeCode.SByte: return (SByte)ul;
488 case TypeCode.Byte: return (Byte)ul;
489 case TypeCode.Int16: return (Int16)ul;
490 case TypeCode.UInt16: return (UInt16)ul;
491 case TypeCode.Int32: return (Int32)ul;
492 case TypeCode.UInt32: return (UInt32)ul;
493 case TypeCode.Int64: return (Int64)ul;
494 case TypeCode.UInt64: return ul;
495 case TypeCode.Single: return (Single)ul;
496 case TypeCode.Double: return (Double)ul;
497 case TypeCode.Decimal: return (Decimal)ul;
498 case TypeCode.DateTime: return new DateTime((Int64)ul);
499 case TypeCode.String: return ul.ToString(CultureInfo.InvariantCulture);
501 break;
503 case TypeCode.Single:
504 Single f = ic.ToSingle(null);
505 switch (target){
506 case TypeCode.Boolean: if (f != f) return false; else return f != 0;
507 case TypeCode.Single: return f;
508 case TypeCode.Double: return (Double)f;
509 case TypeCode.Decimal: return (Decimal)f;
510 case TypeCode.String: return Convert.ToString((double)f);
511 default:
512 if (System.Math.Round(f) == f){
513 switch (target){
514 case TypeCode.Char: return (Char)f;
515 case TypeCode.SByte: return (SByte)f;
516 case TypeCode.Byte: return (Byte)f;
517 case TypeCode.Int16: return (Int16)f;
518 case TypeCode.UInt16: return (UInt16)f;
519 case TypeCode.Int32: return (Int32)f;
520 case TypeCode.UInt32: return (UInt32)f;
521 case TypeCode.Int64: return (Int64)f;
522 case TypeCode.UInt64: return (UInt64)f;
523 case TypeCode.DateTime: return new DateTime((Int64)f);
526 break;
528 break;
530 case TypeCode.Double:
531 Double d = ic.ToDouble(null);
532 switch (target){
533 case TypeCode.Boolean: return Convert.ToBoolean(d);
534 case TypeCode.Single: return (float)d;
535 case TypeCode.Double: return d;
536 case TypeCode.Decimal: return (Decimal)d;
537 case TypeCode.String: return Convert.ToString(d);
538 default:
539 if (System.Math.Round(d) == d){
540 switch (target){
541 case TypeCode.Char: return (Char)d;
542 case TypeCode.SByte: return (SByte)d;
543 case TypeCode.Byte: return (Byte)d;
544 case TypeCode.Int16: return (Int16)d;
545 case TypeCode.UInt16: return (UInt16)d;
546 case TypeCode.Int32: return (Int32)d;
547 case TypeCode.UInt32: return (UInt32)d;
548 case TypeCode.Int64: return (Int64)d;
549 case TypeCode.UInt64: return (UInt64)d;
550 case TypeCode.DateTime: return new DateTime((Int64)d);
553 break;
555 break;
557 case TypeCode.Decimal:
558 Decimal dec = ic.ToDecimal(null);
559 switch (target){
560 case TypeCode.Boolean: return dec != 0;
561 case TypeCode.Char: return (Char)Decimal.ToUInt16(dec);
562 case TypeCode.SByte: return Decimal.ToSByte(dec);
563 case TypeCode.Byte: return Decimal.ToByte(dec);
564 case TypeCode.Int16:return Decimal.ToInt16(dec);
565 case TypeCode.UInt16: return Decimal.ToUInt16(dec);
566 case TypeCode.Int32: return Decimal.ToInt32(dec);
567 case TypeCode.UInt32: return Decimal.ToUInt32(dec);
568 case TypeCode.Int64: return Decimal.ToInt64(dec);
569 case TypeCode.UInt64: return Decimal.ToUInt64(dec);
570 case TypeCode.Single: return Decimal.ToSingle(dec);
571 case TypeCode.Double: return Decimal.ToDouble(dec);
572 case TypeCode.Decimal: return dec;
573 case TypeCode.DateTime: return new DateTime(Decimal.ToInt64(dec));
574 case TypeCode.String: return dec.ToString(CultureInfo.InvariantCulture);
576 break;
578 case TypeCode.DateTime:
579 DateTime dt = ic.ToDateTime(null);
580 switch (target){
581 case TypeCode.Boolean:
582 case TypeCode.Char:
583 case TypeCode.SByte:
584 case TypeCode.Byte:
585 case TypeCode.Int16:
586 case TypeCode.UInt16:
587 case TypeCode.Int32:
588 case TypeCode.UInt32:
589 case TypeCode.Int64:
590 case TypeCode.UInt64:
591 case TypeCode.Single:
592 case TypeCode.Double:
593 case TypeCode.Decimal: return Coerce2WithNoTrunctation(dt.Ticks, target);
594 case TypeCode.DateTime: return dt;
595 case TypeCode.String: return dt.ToString(CultureInfo.InvariantCulture);
597 break;
599 case TypeCode.String:
600 String str = ic.ToString(null);
601 switch (target){
602 case TypeCode.Boolean: return Convert.ToBoolean(str, false);
603 case TypeCode.Char:
604 if (str.Length == 1) return str[0];
605 throw new JScriptException(JSError.TypeMismatch);
606 case TypeCode.SByte:
607 case TypeCode.Byte:
608 case TypeCode.Int16:
609 case TypeCode.UInt16:
610 case TypeCode.Int32:
611 case TypeCode.UInt32:
612 case TypeCode.Double: return Coerce2WithNoTrunctation(Convert.ToNumber(str), target);
613 case TypeCode.Single: try {return Single.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
614 case TypeCode.Int64: try {return Int64.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
615 case TypeCode.UInt64: try {return UInt64.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
616 case TypeCode.Decimal: try {return Decimal.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
617 case TypeCode.DateTime:
618 try{
619 return DateTime.Parse(str, CultureInfo.InvariantCulture);
620 }catch{
621 return DatePrototype.getVarDate(DateConstructor.ob.CreateInstance(DatePrototype.ParseDate(str)));
623 case TypeCode.String: return str;
625 break;
627 }}catch(OverflowException){}
628 throw new JScriptException(JSError.TypeMismatch);
631 //Call this routine only for target TypeTokens other than Object and Empty
632 //It special cases the well known types with JScript specific conversion semantics
633 private static Object Coerce2WithTruncationPermitted(Object value, TypeCode target){
634 if (value is EnumWrapper)
635 value = ((EnumWrapper)value).value;
636 if (value is ConstantWrapper)
637 value = ((ConstantWrapper)value).value;
638 IConvertible ic = Convert.GetIConvertible(value);
639 switch (Convert.GetTypeCode(value, ic)){
640 case TypeCode.Empty:
641 switch (target){
642 case TypeCode.DBNull: return DBNull.Value;
643 case TypeCode.Boolean: return false;
644 case TypeCode.Char: return (Char)0;
645 case TypeCode.SByte: return (SByte)0;
646 case TypeCode.Byte: return (Byte)0;
647 case TypeCode.Int16: return (Int16)0;
648 case TypeCode.UInt16: return (UInt16)0;
649 case TypeCode.Int32: return (Int32)0;
650 case TypeCode.UInt32: return (UInt32)0;
651 case TypeCode.Int64: return (Int64)0;
652 case TypeCode.UInt64: return (UInt64)0;
653 case TypeCode.Single: return Single.NaN;
654 case TypeCode.Double: return Double.NaN;
655 case TypeCode.Decimal: return (Decimal)0;
656 case TypeCode.DateTime: return new DateTime((Int64)0);
657 case TypeCode.String: return "undefined";
659 break;
661 case TypeCode.Object:
662 if (value is System.Reflection.Missing || (value is Missing && target != TypeCode.Object)) goto case TypeCode.Empty;
663 switch (target){
664 case TypeCode.Boolean: return Convert.ToBoolean(value, ic);
665 case TypeCode.Char:
666 case TypeCode.SByte:
667 case TypeCode.Byte:
668 case TypeCode.Int16:
669 case TypeCode.UInt16:
670 case TypeCode.Int32:
671 case TypeCode.UInt32:
672 case TypeCode.Int64:
673 case TypeCode.UInt64:
674 case TypeCode.Single:
675 case TypeCode.Double:
676 case TypeCode.Decimal: return Coerce2WithTruncationPermitted(Convert.ToNumber(value, ic), target);
677 case TypeCode.DateTime:
678 if (value is DateObject)
679 return DatePrototype.getVarDate((DateObject)value);
680 else
681 return Coerce2WithTruncationPermitted(Convert.ToNumber(value, ic), target);
682 case TypeCode.String: return Convert.ToString(value, ic);
684 break;
686 case TypeCode.DBNull:
687 switch (target){
688 case TypeCode.DBNull: return DBNull.Value;
689 case TypeCode.Boolean: return false;
690 case TypeCode.Char: return (Char)0;
691 case TypeCode.SByte: return (SByte)0;
692 case TypeCode.Byte: return (Byte)0;
693 case TypeCode.Int16: return (Int16)0;
694 case TypeCode.UInt16: return (UInt16)0;
695 case TypeCode.Int32: return (Int32)0;
696 case TypeCode.UInt32: return (UInt32)0;
697 case TypeCode.Int64: return (Int64)0;
698 case TypeCode.UInt64: return (UInt64)0;
699 case TypeCode.Single: return (Single)0;
700 case TypeCode.Double: return (Double)0;
701 case TypeCode.Decimal: return (Decimal)0;
702 case TypeCode.DateTime: return new DateTime((Int64)0);
703 case TypeCode.String: return "null";
705 break;
707 case TypeCode.Boolean:
708 bool b = ic.ToBoolean(null);
709 int bi = b ? 1 : 0;
710 switch (target){
711 case TypeCode.Boolean: return b;
712 case TypeCode.Char: return (Char)bi;
713 case TypeCode.SByte: return (SByte)bi;
714 case TypeCode.Byte: return (Byte)bi;
715 case TypeCode.Int16: return (Int16)bi;
716 case TypeCode.UInt16: return (UInt16)bi;
717 case TypeCode.Int32: return (Int32)bi;
718 case TypeCode.UInt32: return (UInt32)bi;
719 case TypeCode.Int64: return (Int64)bi;
720 case TypeCode.UInt64: return (UInt64)bi;
721 case TypeCode.Single: return (Single)bi;
722 case TypeCode.Double: return (Double)bi;
723 case TypeCode.Decimal: return (Decimal)bi;
724 case TypeCode.DateTime: return new DateTime((Int64)bi);
725 case TypeCode.String: return b ? "true" : "false";
727 break;
729 case TypeCode.Char:
730 Char ch = ic.ToChar(null);
731 UInt16 us = (UInt16)ch;
732 switch (target){
733 case TypeCode.Boolean: return us != 0;
734 case TypeCode.Char: return ch;
735 case TypeCode.SByte: return (SByte)us;
736 case TypeCode.Byte: return (Byte)us;
737 case TypeCode.Int16: return (Int16)us;
738 case TypeCode.UInt16: return us;
739 case TypeCode.Int32: return (Int32)us;
740 case TypeCode.UInt32: return (UInt32)us;
741 case TypeCode.Int64: return (Int64)us;
742 case TypeCode.UInt64: return (UInt64)us;
743 case TypeCode.Single: return (Single)us;
744 case TypeCode.Double: return (Double)us;
745 case TypeCode.Decimal: return (Decimal)us;
746 case TypeCode.DateTime: return new DateTime((Int64)us);
747 case TypeCode.String: return Char.ToString(ch);
749 break;
751 case TypeCode.SByte:
752 SByte sb = ic.ToSByte(null);
753 switch (target){
754 case TypeCode.Boolean: return sb != 0;
755 case TypeCode.Char: return (Char)sb;
756 case TypeCode.SByte: return sb;
757 case TypeCode.Byte: return (Byte)sb;
758 case TypeCode.Int16: return (Int16)sb;
759 case TypeCode.UInt16: return (UInt16)sb;
760 case TypeCode.Int32: return (Int32)sb;
761 case TypeCode.UInt32: return (UInt32)sb;
762 case TypeCode.Int64: return (Int64)sb;
763 case TypeCode.UInt64: return (UInt64)sb;
764 case TypeCode.Single: return (Single)sb;
765 case TypeCode.Double: return (Double)sb;
766 case TypeCode.Decimal: return (Decimal)sb;
767 case TypeCode.DateTime: return new DateTime((Int64)sb);
768 case TypeCode.String: return sb.ToString(CultureInfo.InvariantCulture);
770 break;
772 case TypeCode.Byte:
773 Byte ub = ic.ToByte(null);
774 switch (target){
775 case TypeCode.Boolean: return ub != 0;
776 case TypeCode.Char: return (Char)ub;
777 case TypeCode.SByte: return (SByte)ub;
778 case TypeCode.Byte: return ub;
779 case TypeCode.Int16: return (Int16)ub;
780 case TypeCode.UInt16: return (UInt16)ub;
781 case TypeCode.Int32: return (Int32)ub;
782 case TypeCode.UInt32: return (UInt32)ub;
783 case TypeCode.Int64: return (Int64)ub;
784 case TypeCode.UInt64: return (UInt64)ub;
785 case TypeCode.Single: return (Single)ub;
786 case TypeCode.Double: return (Double)ub;
787 case TypeCode.Decimal: return (Decimal)ub;
788 case TypeCode.DateTime: return new DateTime((Int64)ub);
789 case TypeCode.String: return ub.ToString(CultureInfo.InvariantCulture);
791 break;
793 case TypeCode.Int16:
794 Int16 s = ic.ToInt16(null);
795 switch (target){
796 case TypeCode.Boolean: return s != 0;
797 case TypeCode.Char: return (Char)s;
798 case TypeCode.SByte: return (SByte)s;
799 case TypeCode.Byte: return (Byte)s;
800 case TypeCode.Int16: return s;
801 case TypeCode.UInt16: return (UInt16)s;
802 case TypeCode.Int32: return (Int32)s;
803 case TypeCode.UInt32: return (UInt32)s;
804 case TypeCode.Int64: return (Int64)s;
805 case TypeCode.UInt64: return (UInt64)s;
806 case TypeCode.Single: return (Single)s;
807 case TypeCode.Double: return (Double)s;
808 case TypeCode.Decimal: return (Decimal)s;
809 case TypeCode.DateTime: return new DateTime((Int64)s);
810 case TypeCode.String: return s.ToString(CultureInfo.InvariantCulture);
812 break;
814 case TypeCode.UInt16:
815 us = ic.ToUInt16(null);
816 switch (target){
817 case TypeCode.Boolean: return us != 0;
818 case TypeCode.Char: return (Char)us;
819 case TypeCode.SByte: return (SByte)us;
820 case TypeCode.Byte: return (Byte)us;
821 case TypeCode.Int16: return (Int16)us;
822 case TypeCode.UInt16: return us;
823 case TypeCode.Int32: return (Int32)us;
824 case TypeCode.UInt32: return (UInt32)us;
825 case TypeCode.Int64: return (Int64)us;
826 case TypeCode.UInt64: return (UInt64)us;
827 case TypeCode.Single: return (Single)us;
828 case TypeCode.Double: return (Double)us;
829 case TypeCode.Decimal: return (Decimal)us;
830 case TypeCode.DateTime: return new DateTime((Int64)us);
831 case TypeCode.String: return us.ToString(CultureInfo.InvariantCulture);
833 break;
835 case TypeCode.Int32:
836 Int32 i = ic.ToInt32(null);
837 switch (target){
838 case TypeCode.Boolean: return i != 0;
839 case TypeCode.Char: return (Char)i;
840 case TypeCode.SByte: return (SByte)i;
841 case TypeCode.Byte: return (Byte)i;
842 case TypeCode.Int16: return (Int16)i;
843 case TypeCode.UInt16: return (UInt16)i;
844 case TypeCode.Int32: return i;
845 case TypeCode.UInt32: return (UInt32)i;
846 case TypeCode.Int64: return (Int64)i;
847 case TypeCode.UInt64: return (UInt64)i;
848 case TypeCode.Single: return (Single)i;
849 case TypeCode.Double: return (Double)i;
850 case TypeCode.Decimal: return (Decimal)i;
851 case TypeCode.DateTime: return new DateTime((Int64)i);
852 case TypeCode.String: return i.ToString(CultureInfo.InvariantCulture);
854 break;
856 case TypeCode.UInt32:
857 UInt32 ui = ic.ToUInt32(null);
858 switch (target){
859 case TypeCode.Boolean: return ui != 0;
860 case TypeCode.Char: return (Char)ui;
861 case TypeCode.SByte: return (SByte)ui;
862 case TypeCode.Byte: return (Byte)ui;
863 case TypeCode.Int16: return (Int16)ui;
864 case TypeCode.UInt16: return (UInt16)ui;
865 case TypeCode.Int32: return (Int32)ui;
866 case TypeCode.UInt32: return ui;
867 case TypeCode.Int64: return (Int64)ui;
868 case TypeCode.UInt64: return (UInt64)ui;
869 case TypeCode.Single: return (Single)ui;
870 case TypeCode.Double: return (Double)ui;
871 case TypeCode.Decimal: return (Decimal)ui;
872 case TypeCode.DateTime: return new DateTime((Int64)ui);
873 case TypeCode.String: return ui.ToString(CultureInfo.InvariantCulture);
875 break;
877 case TypeCode.Int64:
878 Int64 l = ic.ToInt64(null);
879 switch (target){
880 case TypeCode.Boolean: return l != 0;
881 case TypeCode.Char: return (Char)l;
882 case TypeCode.SByte: return (SByte)l;
883 case TypeCode.Byte: return (Byte)l;
884 case TypeCode.Int16: return (Int16)l;
885 case TypeCode.UInt16: return (UInt16)l;
886 case TypeCode.Int32: return (Int32)l;
887 case TypeCode.UInt32: return (UInt32)l;
888 case TypeCode.Int64: return l;
889 case TypeCode.UInt64: return (UInt64)l;
890 case TypeCode.Single: return (Single)l;
891 case TypeCode.Double: return (Double)l;
892 case TypeCode.Decimal: return (Decimal)l;
893 case TypeCode.DateTime: return new DateTime(l);
894 case TypeCode.String: return l.ToString(CultureInfo.InvariantCulture);
896 break;
898 case TypeCode.UInt64:
899 UInt64 ul = ic.ToUInt64(null);
900 switch (target){
901 case TypeCode.Boolean: return ul != 0;
902 case TypeCode.Char: return (Char)ul;
903 case TypeCode.SByte: return (SByte)ul;
904 case TypeCode.Byte: return (Byte)ul;
905 case TypeCode.Int16: return (Int16)ul;
906 case TypeCode.UInt16: return (UInt16)ul;
907 case TypeCode.Int32: return (Int32)ul;
908 case TypeCode.UInt32: return (UInt32)ul;
909 case TypeCode.Int64: return (Int64)ul;
910 case TypeCode.UInt64: return ul;
911 case TypeCode.Single: return (Single)ul;
912 case TypeCode.Double: return (Double)ul;
913 case TypeCode.Decimal: return (Decimal)ul;
914 case TypeCode.DateTime: return new DateTime((Int64)ul);
915 case TypeCode.String: return ul.ToString(CultureInfo.InvariantCulture);
917 break;
919 case TypeCode.Single:
920 Single f = ic.ToSingle(null);
921 switch (target){
922 case TypeCode.Boolean: if (f != f) return false; else return f != 0;
923 case TypeCode.Single: return f;
924 case TypeCode.Double: return (Double)f;
925 case TypeCode.Decimal: return (Decimal)f;
926 case TypeCode.String: return Convert.ToString((double)f);
929 l = Runtime.DoubleToInt64(f);
930 switch (target){
931 case TypeCode.Char: return (Char)l;
932 case TypeCode.SByte: return (SByte)l;
933 case TypeCode.Byte: return (Byte)l;
934 case TypeCode.Int16: return (Int16)l;
935 case TypeCode.UInt16: return (UInt16)l;
936 case TypeCode.Int32: return (Int32)l;
937 case TypeCode.UInt32: return (UInt32)l;
938 case TypeCode.Int64: return (Int64)l;
939 case TypeCode.UInt64: return (UInt64)l;
940 case TypeCode.DateTime: return new DateTime((Int64)l);
942 break;
944 case TypeCode.Double:
945 Double d = ic.ToDouble(null);
946 switch (target){
947 case TypeCode.Boolean: return Convert.ToBoolean(d);
948 case TypeCode.Single: return (float)d;
949 case TypeCode.Double: return d;
950 case TypeCode.Decimal: return (Decimal)d;
951 case TypeCode.String: return Convert.ToString(d);
953 l = Runtime.DoubleToInt64(d);
954 switch (target) {
955 case TypeCode.Char: return (Char)l;
956 case TypeCode.SByte: return (SByte)l;
957 case TypeCode.Byte: return (Byte)l;
958 case TypeCode.Int16: return (Int16)l;
959 case TypeCode.UInt16: return (UInt16)l;
960 case TypeCode.Int32: return (Int32)l;
961 case TypeCode.UInt32: return (UInt32)l;
962 case TypeCode.Int64: return (Int64)l;
963 case TypeCode.UInt64: return (UInt64)l;
964 case TypeCode.DateTime: return new DateTime((Int64)l);
966 break;
968 case TypeCode.Decimal:
969 Decimal dec = ic.ToDecimal(null);
970 switch (target){
971 case TypeCode.Boolean: return dec != 0;
972 case TypeCode.Char:
973 case TypeCode.SByte:
974 case TypeCode.Byte:
975 case TypeCode.Int16:
976 case TypeCode.UInt16:
977 case TypeCode.Int32:
978 case TypeCode.UInt32:
979 case TypeCode.Int64:
980 case TypeCode.UInt64:
981 return Coerce2WithTruncationPermitted(Runtime.UncheckedDecimalToInt64(dec), target);
982 case TypeCode.Single: return Decimal.ToSingle(dec);
983 case TypeCode.Double: return Decimal.ToDouble(dec);
984 case TypeCode.Decimal: return dec;
985 case TypeCode.DateTime: return new DateTime(Runtime.UncheckedDecimalToInt64(dec));
986 case TypeCode.String: return dec.ToString(CultureInfo.InvariantCulture);
988 break;
990 case TypeCode.DateTime:
991 DateTime dt = ic.ToDateTime(null);
992 switch (target){
993 case TypeCode.Boolean:
994 case TypeCode.Char:
995 case TypeCode.SByte:
996 case TypeCode.Byte:
997 case TypeCode.Int16:
998 case TypeCode.UInt16:
999 case TypeCode.Int32:
1000 case TypeCode.UInt32:
1001 case TypeCode.Int64:
1002 case TypeCode.UInt64:
1003 case TypeCode.Single:
1004 case TypeCode.Double:
1005 case TypeCode.Decimal: return Coerce2WithTruncationPermitted(dt.Ticks, target);
1006 case TypeCode.DateTime: return dt;
1007 case TypeCode.String: return dt.ToString(CultureInfo.InvariantCulture);
1009 break;
1011 case TypeCode.String:
1012 String str = ic.ToString(null);
1013 switch (target){
1014 case TypeCode.Boolean: return Convert.ToBoolean(str, false);
1015 case TypeCode.Char:
1016 if (str.Length == 1) return str[0];
1017 throw new JScriptException(JSError.TypeMismatch);
1018 case TypeCode.SByte:
1019 case TypeCode.Byte:
1020 case TypeCode.Int16:
1021 case TypeCode.UInt16:
1022 case TypeCode.Int32:
1023 case TypeCode.UInt32:
1024 case TypeCode.Double: return Coerce2WithTruncationPermitted(Convert.ToNumber(str), target);
1025 case TypeCode.Single: try {return Single.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
1026 case TypeCode.Int64:
1027 try{
1028 return Int64.Parse(str, CultureInfo.InvariantCulture);
1029 }catch{
1030 try{
1031 return (long)UInt64.Parse(str, CultureInfo.InvariantCulture);
1032 }catch{
1033 goto case TypeCode.Double;
1036 case TypeCode.UInt64: try {return UInt64.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
1037 case TypeCode.Decimal: try {return Decimal.Parse(str, CultureInfo.InvariantCulture);}catch{goto case TypeCode.Double;}
1038 case TypeCode.DateTime: return DateTime.Parse(str, CultureInfo.InvariantCulture);
1039 case TypeCode.String: return str;
1041 break;
1043 throw new JScriptException(JSError.TypeMismatch);
1046 //This function emits a compiled version of Coerce for a particular (source_type, target_type) pair.
1047 //It assumes that an operand of source_type is already on the operand stack. It consumes this operand
1048 //and leaves a result of target_type in its place.
1049 internal static void Emit(AST ast, ILGenerator il, Type source_type, Type target_type){
1050 Convert.Emit(ast, il, source_type, target_type, false);
1053 internal static void Emit(AST ast, ILGenerator il, Type source_type, Type target_type, bool truncationPermitted){
1054 if (source_type == target_type) return;
1055 if (target_type == Typeob.Void){
1056 il.Emit(OpCodes.Pop);
1057 return;
1059 if (target_type.IsEnum){
1060 if (source_type == Typeob.String || source_type == Typeob.Object){
1061 il.Emit(OpCodes.Ldtoken, target_type);
1062 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
1063 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
1064 il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
1065 Convert.EmitUnbox(il, target_type, Type.GetTypeCode(Convert.GetUnderlyingType(target_type)));
1066 }else
1067 Convert.Emit(ast, il, source_type, Convert.GetUnderlyingType(target_type));
1068 return;
1070 if (source_type.IsEnum){
1071 if (target_type.IsPrimitive){
1072 Convert.Emit(ast, il, Convert.GetUnderlyingType(source_type), target_type);
1073 return;
1075 if (target_type == Typeob.Object || target_type == Typeob.Enum){
1076 il.Emit(OpCodes.Box, source_type);
1077 return;
1079 if (target_type == Typeob.String){
1080 il.Emit(OpCodes.Box, source_type);
1081 ConstantWrapper.TranslateToILInt(il, 0);
1082 il.Emit(OpCodes.Call, CompilerGlobals.toStringMethod);
1083 return;
1087 while (source_type is TypeBuilder){
1088 source_type = source_type.BaseType;
1089 if (source_type == null) source_type = Typeob.Object; //It is an interface
1090 if (source_type == target_type) return;
1093 if (source_type.IsArray && target_type.IsArray)
1094 //This should only be called if the two types are known to be compatible, so:
1095 return;
1097 TypeCode source = Type.GetTypeCode(source_type);
1098 TypeCode target = target_type is TypeBuilder ? TypeCode.Object : Type.GetTypeCode(target_type);
1099 switch (source){
1100 case TypeCode.Empty: //can never occur
1101 return;
1103 case TypeCode.Object:
1104 if (source_type == Typeob.Void){
1105 il.Emit(OpCodes.Ldnull);
1106 source_type = Typeob.Object;
1108 switch (target){
1109 case TypeCode.Object:
1110 //The conversion from function object to delegate never happens here. ConstantWrapper takes care of it.
1111 //First check for array target type or TypeBuilder target type. These do not support IsAssignableFrom.
1112 if (target_type.IsArray || target_type == Typeob.Array){
1113 if (source_type == Typeob.ArrayObject || source_type == Typeob.Object){
1114 if (target_type.IsArray)
1115 il.Emit(OpCodes.Ldtoken, target_type.GetElementType());
1116 else
1117 il.Emit(OpCodes.Ldtoken, Typeob.Object);
1118 il.Emit(OpCodes.Call, CompilerGlobals.toNativeArrayMethod);
1120 il.Emit(OpCodes.Castclass, target_type);
1121 return;
1122 }else if (target_type is TypeBuilder){
1123 il.Emit(OpCodes.Castclass, target_type);
1124 return;
1125 }else if (target_type == Typeob.Enum && source_type.BaseType == Typeob.Enum){
1126 il.Emit(OpCodes.Box, source_type);
1127 return;
1128 }else if (target_type == Typeob.Object || target_type.IsAssignableFrom(source_type)){
1129 if (source_type.IsValueType)
1130 il.Emit(OpCodes.Box, source_type);
1131 return;
1134 if (Typeob.JSObject.IsAssignableFrom(target_type)){
1135 if (source_type.IsValueType)
1136 il.Emit(OpCodes.Box, source_type);
1137 ast.EmitILToLoadEngine(il);
1138 il.Emit(OpCodes.Call, CompilerGlobals.toObject2Method); //Do this here so that we need not pass engine to Coerce
1139 il.Emit(OpCodes.Castclass, target_type);
1140 return;
1143 if (Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1144 return;
1146 //Either no conversion is possible, or not enough information is available at compile time.
1147 //PartialEvaluator is supposed to give errors when conversions are known to be impossible.
1148 //Defer to run-time type checking
1149 if (target_type.IsValueType || target_type.IsArray){
1150 //Some runtime conversions might be possible
1151 il.Emit(OpCodes.Ldtoken, target_type);
1152 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
1153 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
1154 il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
1156 if (target_type.IsValueType)
1157 Convert.EmitUnbox(il, target_type, target);
1158 else
1159 il.Emit(OpCodes.Castclass, target_type);
1160 return;
1162 case TypeCode.Boolean:
1163 if (source_type.IsValueType)
1164 il.Emit(OpCodes.Box, source_type);
1165 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
1166 il.Emit(OpCodes.Call, CompilerGlobals.toBooleanMethod);
1167 return;
1169 case TypeCode.Single:
1170 if (source_type.IsValueType)
1171 il.Emit(OpCodes.Box, source_type);
1172 il.Emit(OpCodes.Call, CompilerGlobals.toNumberMethod);
1173 il.Emit(OpCodes.Conv_R4);
1174 return;
1176 case TypeCode.Double:
1177 if (source_type.IsValueType)
1178 il.Emit(OpCodes.Box, source_type);
1179 il.Emit(OpCodes.Call, CompilerGlobals.toNumberMethod);
1180 return;
1182 case TypeCode.Char:
1183 case TypeCode.SByte:
1184 case TypeCode.Byte:
1185 case TypeCode.Int16:
1186 case TypeCode.UInt16:
1187 case TypeCode.Int32:
1188 case TypeCode.UInt32:
1189 case TypeCode.Int64:
1190 case TypeCode.UInt64:
1191 case TypeCode.Decimal:
1192 case TypeCode.DateTime:
1193 if (source_type.IsValueType)
1194 il.Emit(OpCodes.Box, source_type);
1195 if (truncationPermitted && target == TypeCode.Int32){
1196 il.Emit(OpCodes.Call, CompilerGlobals.toInt32Method);
1197 return;
1198 }else{
1199 ConstantWrapper.TranslateToILInt(il, (int)target);
1200 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
1201 il.Emit(OpCodes.Call, CompilerGlobals.coerce2Method);
1203 if (target_type.IsValueType)
1204 Convert.EmitUnbox(il, target_type, target);
1205 return;
1207 case TypeCode.String:
1208 if (source_type.IsValueType)
1209 il.Emit(OpCodes.Box, source_type);
1210 if (truncationPermitted) //explict cast to type string
1211 il.Emit(OpCodes.Castclass, Typeob.String);
1212 else{
1213 ConstantWrapper.TranslateToILInt(il, 1);
1214 il.Emit(OpCodes.Call, CompilerGlobals.toStringMethod);
1216 return;
1218 return;
1220 case TypeCode.DBNull:
1221 if (source_type.IsValueType) //Not likely, but a hacker might cause this to be true.
1222 il.Emit(OpCodes.Box, source_type);
1223 if (target == TypeCode.Object || (target == TypeCode.String && !truncationPermitted)){
1224 if (target_type == Typeob.Object)
1225 return;
1226 if (!target_type.IsValueType){
1227 il.Emit(OpCodes.Pop);
1228 il.Emit(OpCodes.Ldnull);
1229 return;
1232 if (target_type.IsValueType){
1233 il.Emit(OpCodes.Ldtoken, target_type);
1234 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
1235 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
1236 il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
1237 Convert.EmitUnbox(il, target_type, target);
1238 }else{
1239 ConstantWrapper.TranslateToILInt(il, (int)target);
1240 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
1241 il.Emit(OpCodes.Call, CompilerGlobals.coerce2Method); //constructs and boxes whatever value is needed
1243 return;
1245 case TypeCode.Boolean:
1246 switch (target){
1247 case TypeCode.Object:
1248 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1249 return;
1250 il.Emit(OpCodes.Box, source_type);
1251 Convert.Emit(ast, il, Typeob.Object, target_type);
1252 return;
1253 case TypeCode.Boolean:
1254 case TypeCode.Char:
1255 case TypeCode.SByte:
1256 case TypeCode.Int16:
1257 case TypeCode.Int32:
1258 case TypeCode.Byte:
1259 case TypeCode.UInt16:
1260 case TypeCode.UInt32:
1261 return;
1262 case TypeCode.Int64:
1263 case TypeCode.UInt64:
1264 il.Emit(OpCodes.Conv_U8);
1265 return;
1266 case TypeCode.Single:
1267 il.Emit(OpCodes.Conv_R4);
1268 return;
1269 case TypeCode.Double:
1270 il.Emit(OpCodes.Conv_R8);
1271 return;
1272 case TypeCode.Decimal:
1273 il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
1274 return;
1275 case TypeCode.DateTime:
1276 il.Emit(OpCodes.Conv_I8);
1277 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1278 return;
1279 case TypeCode.String:
1280 Label false_label = il.DefineLabel();
1281 Label end_label = il.DefineLabel();
1282 il.Emit(OpCodes.Brfalse, false_label);
1283 il.Emit(OpCodes.Ldstr, "true");
1284 il.Emit(OpCodes.Br, end_label);
1285 il.MarkLabel(false_label);
1286 il.Emit(OpCodes.Ldstr, "false");
1287 il.MarkLabel(end_label);
1288 return;
1290 break;
1292 case TypeCode.SByte:
1293 switch (target){
1294 case TypeCode.Object:
1295 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1296 return;
1297 il.Emit(OpCodes.Box, source_type);
1298 Convert.Emit(ast, il, Typeob.Object, target_type);
1299 return;
1300 case TypeCode.SByte:
1301 case TypeCode.Int16:
1302 case TypeCode.Int32:
1303 return;
1304 case TypeCode.Byte:
1305 if (truncationPermitted)
1306 il.Emit(OpCodes.Conv_U1);
1307 else
1308 il.Emit(OpCodes.Conv_Ovf_U1);
1309 return;
1310 case TypeCode.Char:
1311 case TypeCode.UInt16:
1312 if (truncationPermitted)
1313 il.Emit(OpCodes.Conv_U2);
1314 else
1315 il.Emit(OpCodes.Conv_Ovf_U2);
1316 return;
1317 case TypeCode.UInt32:
1318 if (truncationPermitted)
1319 il.Emit(OpCodes.Conv_U4);
1320 else
1321 il.Emit(OpCodes.Conv_Ovf_U4);
1322 return;
1323 case TypeCode.Int64:
1324 il.Emit(OpCodes.Conv_I8);
1325 return;
1326 case TypeCode.UInt64:
1327 if (truncationPermitted)
1328 il.Emit(OpCodes.Conv_I8);
1329 else
1330 il.Emit(OpCodes.Conv_Ovf_U8);
1331 return;
1332 case TypeCode.Single:
1333 case TypeCode.Double:
1334 il.Emit(OpCodes.Conv_R8);
1335 return;
1336 case TypeCode.Boolean:
1337 il.Emit(OpCodes.Ldc_I4_0);
1338 il.Emit(OpCodes.Ceq);
1339 il.Emit(OpCodes.Ldc_I4_0);
1340 il.Emit(OpCodes.Ceq);
1341 return;
1342 case TypeCode.Decimal:
1343 il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
1344 return;
1345 case TypeCode.DateTime:
1346 il.Emit(OpCodes.Conv_I8);
1347 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1348 return;
1349 case TypeCode.String:
1350 Convert.EmitLdloca(il, Typeob.Int32);
1351 il.Emit(OpCodes.Call, CompilerGlobals.int32ToStringMethod);
1352 return;
1354 break;
1356 case TypeCode.Byte:
1357 switch (target){
1358 case TypeCode.Object:
1359 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1360 return;
1361 il.Emit(OpCodes.Box, source_type);
1362 Convert.Emit(ast, il, Typeob.Object, target_type);
1363 return;
1364 case TypeCode.SByte:
1365 if (truncationPermitted)
1366 il.Emit(OpCodes.Conv_I1);
1367 else
1368 il.Emit(OpCodes.Conv_Ovf_I1_Un);
1369 return;
1370 case TypeCode.Byte:
1371 case TypeCode.Int16:
1372 case TypeCode.Char:
1373 case TypeCode.UInt16:
1374 case TypeCode.Int32:
1375 case TypeCode.UInt32:
1376 return;
1377 case TypeCode.Int64:
1378 case TypeCode.UInt64:
1379 il.Emit(OpCodes.Conv_U8);
1380 return;
1381 case TypeCode.Single:
1382 case TypeCode.Double:
1383 il.Emit(OpCodes.Conv_R_Un);
1384 return;
1385 case TypeCode.Boolean:
1386 il.Emit(OpCodes.Ldc_I4_0);
1387 il.Emit(OpCodes.Ceq);
1388 il.Emit(OpCodes.Ldc_I4_0);
1389 il.Emit(OpCodes.Ceq);
1390 return;
1391 case TypeCode.Decimal:
1392 il.Emit(OpCodes.Call, CompilerGlobals.uint32ToDecimalMethod);
1393 return;
1394 case TypeCode.DateTime:
1395 il.Emit(OpCodes.Conv_I8);
1396 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1397 return;
1398 case TypeCode.String:
1399 Convert.EmitLdloca(il, Typeob.UInt32);
1400 il.Emit(OpCodes.Call, CompilerGlobals.uint32ToStringMethod);
1401 return;
1403 break;
1405 case TypeCode.Int16:
1406 switch (target){
1407 case TypeCode.Object:
1408 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1409 return;
1410 il.Emit(OpCodes.Box, source_type);
1411 Convert.Emit(ast, il, Typeob.Object, target_type);
1412 return;
1413 case TypeCode.SByte:
1414 if (truncationPermitted)
1415 il.Emit(OpCodes.Conv_I1);
1416 else
1417 il.Emit(OpCodes.Conv_Ovf_I1);
1418 return;
1419 case TypeCode.Int16:
1420 case TypeCode.Int32:
1421 return;
1422 case TypeCode.Byte:
1423 if (truncationPermitted)
1424 il.Emit(OpCodes.Conv_U1);
1425 else
1426 il.Emit(OpCodes.Conv_Ovf_U1);
1427 return;
1428 case TypeCode.Char:
1429 case TypeCode.UInt16:
1430 if (truncationPermitted)
1431 il.Emit(OpCodes.Conv_U2);
1432 else
1433 il.Emit(OpCodes.Conv_Ovf_U2);
1434 return;
1435 case TypeCode.UInt32:
1436 if (truncationPermitted)
1437 il.Emit(OpCodes.Conv_U4);
1438 else
1439 il.Emit(OpCodes.Conv_Ovf_U4);
1440 return;
1441 case TypeCode.Int64:
1442 il.Emit(OpCodes.Conv_I8);
1443 return;
1444 case TypeCode.UInt64:
1445 if (truncationPermitted)
1446 il.Emit(OpCodes.Conv_I8);
1447 else
1448 il.Emit(OpCodes.Conv_Ovf_U8);
1449 return;
1450 case TypeCode.Single:
1451 case TypeCode.Double:
1452 il.Emit(OpCodes.Conv_R8);
1453 return;
1454 case TypeCode.Boolean:
1455 il.Emit(OpCodes.Ldc_I4_0);
1456 il.Emit(OpCodes.Ceq);
1457 il.Emit(OpCodes.Ldc_I4_0);
1458 il.Emit(OpCodes.Ceq);
1459 return;
1460 case TypeCode.Decimal:
1461 il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
1462 return;
1463 case TypeCode.DateTime:
1464 il.Emit(OpCodes.Conv_I8);
1465 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1466 return;
1467 case TypeCode.String:
1468 Convert.EmitLdloca(il, Typeob.Int32);
1469 il.Emit(OpCodes.Call, CompilerGlobals.int32ToStringMethod);
1470 return;
1472 break;
1474 case TypeCode.Char:
1475 case TypeCode.UInt16:
1476 switch (target){
1477 case TypeCode.Object:
1478 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1479 return;
1480 il.Emit(OpCodes.Box, source_type);
1481 Convert.Emit(ast, il, Typeob.Object, target_type);
1482 return;
1483 case TypeCode.SByte:
1484 if (truncationPermitted)
1485 il.Emit(OpCodes.Conv_I1);
1486 else
1487 il.Emit(OpCodes.Conv_Ovf_I1);
1488 return;
1489 case TypeCode.Byte:
1490 if (truncationPermitted)
1491 il.Emit(OpCodes.Conv_U1);
1492 else
1493 il.Emit(OpCodes.Conv_Ovf_U1);
1494 return;
1495 case TypeCode.Int16:
1496 if (truncationPermitted)
1497 il.Emit(OpCodes.Conv_I2);
1498 else
1499 il.Emit(OpCodes.Conv_Ovf_I2);
1500 return;
1501 case TypeCode.Char:
1502 case TypeCode.UInt16:
1503 case TypeCode.Int32:
1504 case TypeCode.UInt32:
1505 return;
1506 case TypeCode.Int64:
1507 il.Emit(OpCodes.Conv_I8);
1508 return;
1509 case TypeCode.UInt64:
1510 il.Emit(OpCodes.Conv_U8);
1511 return;
1512 case TypeCode.Single:
1513 case TypeCode.Double:
1514 il.Emit(OpCodes.Conv_R_Un);
1515 return;
1516 case TypeCode.Boolean:
1517 il.Emit(OpCodes.Ldc_I4_0);
1518 il.Emit(OpCodes.Ceq);
1519 il.Emit(OpCodes.Ldc_I4_0);
1520 il.Emit(OpCodes.Ceq);
1521 return;
1522 case TypeCode.Decimal:
1523 il.Emit(OpCodes.Call, CompilerGlobals.uint32ToDecimalMethod);
1524 return;
1525 case TypeCode.DateTime:
1526 il.Emit(OpCodes.Conv_I8);
1527 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1528 return;
1529 case TypeCode.String:
1530 if (source == TypeCode.Char)
1531 il.Emit(OpCodes.Call, CompilerGlobals.convertCharToStringMethod);
1532 else{
1533 Convert.EmitLdloca(il, Typeob.UInt32);
1534 il.Emit(OpCodes.Call, CompilerGlobals.uint32ToStringMethod);
1536 return;
1538 break;
1540 case TypeCode.Int32:
1541 switch (target){
1542 case TypeCode.Object:
1543 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1544 return;
1545 il.Emit(OpCodes.Box, source_type);
1546 Convert.Emit(ast, il, Typeob.Object, target_type);
1547 return;
1548 case TypeCode.SByte:
1549 if (truncationPermitted)
1550 il.Emit(OpCodes.Conv_I1);
1551 else
1552 il.Emit(OpCodes.Conv_Ovf_I1);
1553 return;
1554 case TypeCode.Int16:
1555 if (truncationPermitted)
1556 il.Emit(OpCodes.Conv_I2);
1557 else
1558 il.Emit(OpCodes.Conv_Ovf_I2);
1559 return;
1560 case TypeCode.Int32:
1561 return;
1562 case TypeCode.Byte:
1563 if (truncationPermitted)
1564 il.Emit(OpCodes.Conv_U1);
1565 else
1566 il.Emit(OpCodes.Conv_Ovf_U1);
1567 return;
1568 case TypeCode.Char:
1569 case TypeCode.UInt16:
1570 if (truncationPermitted)
1571 il.Emit(OpCodes.Conv_U2);
1572 else
1573 il.Emit(OpCodes.Conv_Ovf_U2);
1574 return;
1575 case TypeCode.UInt32:
1576 if (truncationPermitted)
1577 il.Emit(OpCodes.Conv_U4);
1578 else
1579 il.Emit(OpCodes.Conv_Ovf_U4);
1580 return;
1581 case TypeCode.Int64:
1582 il.Emit(OpCodes.Conv_I8);
1583 return;
1584 case TypeCode.UInt64:
1585 if (truncationPermitted)
1586 il.Emit(OpCodes.Conv_U8);
1587 else
1588 il.Emit(OpCodes.Conv_Ovf_U8);
1589 return;
1590 case TypeCode.Single:
1591 case TypeCode.Double:
1592 il.Emit(OpCodes.Conv_R8);
1593 return;
1594 case TypeCode.Boolean:
1595 il.Emit(OpCodes.Ldc_I4_0);
1596 il.Emit(OpCodes.Ceq);
1597 il.Emit(OpCodes.Ldc_I4_0);
1598 il.Emit(OpCodes.Ceq);
1599 return;
1600 case TypeCode.Decimal:
1601 il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
1602 return;
1603 case TypeCode.DateTime:
1604 il.Emit(OpCodes.Conv_I8);
1605 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1606 return;
1607 case TypeCode.String:
1608 Convert.EmitLdloca(il, Typeob.Int32);
1609 il.Emit(OpCodes.Call, CompilerGlobals.int32ToStringMethod);
1610 return;
1612 break;
1614 case TypeCode.UInt32:
1615 switch (target){
1616 case TypeCode.Object:
1617 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1618 return;
1619 il.Emit(OpCodes.Box, source_type);
1620 Convert.Emit(ast, il, Typeob.Object, target_type);
1621 return;
1622 case TypeCode.SByte:
1623 if (truncationPermitted)
1624 il.Emit(OpCodes.Conv_I1);
1625 else
1626 il.Emit(OpCodes.Conv_Ovf_I1);
1627 return;
1628 case TypeCode.Byte:
1629 if (truncationPermitted)
1630 il.Emit(OpCodes.Conv_U1);
1631 else
1632 il.Emit(OpCodes.Conv_Ovf_U1);
1633 return;
1634 case TypeCode.Int16:
1635 if (truncationPermitted)
1636 il.Emit(OpCodes.Conv_I2);
1637 else
1638 il.Emit(OpCodes.Conv_Ovf_I2);
1639 return;
1640 case TypeCode.Char:
1641 case TypeCode.UInt16:
1642 if (truncationPermitted)
1643 il.Emit(OpCodes.Conv_U2);
1644 else
1645 il.Emit(OpCodes.Conv_Ovf_U2);
1646 return;
1647 case TypeCode.Int32:
1648 if (truncationPermitted)
1649 il.Emit(OpCodes.Conv_I4);
1650 else
1651 il.Emit(OpCodes.Conv_Ovf_I4_Un);
1652 return;
1653 case TypeCode.UInt32:
1654 return;
1655 case TypeCode.Int64:
1656 il.Emit(OpCodes.Conv_I8);
1657 return;
1658 case TypeCode.UInt64:
1659 il.Emit(OpCodes.Conv_U8);
1660 return;
1661 case TypeCode.Single:
1662 case TypeCode.Double:
1663 il.Emit(OpCodes.Conv_R_Un);
1664 return;
1665 case TypeCode.Boolean:
1666 il.Emit(OpCodes.Ldc_I4_0);
1667 il.Emit(OpCodes.Ceq);
1668 il.Emit(OpCodes.Ldc_I4_0);
1669 il.Emit(OpCodes.Ceq);
1670 return;
1671 case TypeCode.Decimal:
1672 il.Emit(OpCodes.Call, CompilerGlobals.uint32ToDecimalMethod);
1673 return;
1674 case TypeCode.DateTime:
1675 il.Emit(OpCodes.Conv_I8);
1676 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1677 return;
1678 case TypeCode.String:
1679 Convert.EmitLdloca(il, Typeob.UInt32);
1680 il.Emit(OpCodes.Call, CompilerGlobals.uint32ToStringMethod);
1681 return;
1683 break;
1685 case TypeCode.Int64:
1686 switch (target){
1687 case TypeCode.Object:
1688 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1689 return;
1690 il.Emit(OpCodes.Box, source_type);
1691 Convert.Emit(ast, il, Typeob.Object, target_type);
1692 return;
1693 case TypeCode.SByte:
1694 if (truncationPermitted)
1695 il.Emit(OpCodes.Conv_I1);
1696 else
1697 il.Emit(OpCodes.Conv_Ovf_I1);
1698 return;
1699 case TypeCode.Int16:
1700 if (truncationPermitted)
1701 il.Emit(OpCodes.Conv_I2);
1702 else
1703 il.Emit(OpCodes.Conv_Ovf_I2);
1704 return;
1705 case TypeCode.Int32:
1706 if (truncationPermitted)
1707 il.Emit(OpCodes.Conv_I4);
1708 else
1709 il.Emit(OpCodes.Conv_Ovf_I4);
1710 return;
1711 case TypeCode.Byte:
1712 if (truncationPermitted)
1713 il.Emit(OpCodes.Conv_U1);
1714 else
1715 il.Emit(OpCodes.Conv_Ovf_U1);
1716 return;
1717 case TypeCode.Char:
1718 case TypeCode.UInt16:
1719 if (truncationPermitted)
1720 il.Emit(OpCodes.Conv_U2);
1721 else
1722 il.Emit(OpCodes.Conv_Ovf_U2);
1723 return;
1724 case TypeCode.UInt32:
1725 if (truncationPermitted)
1726 il.Emit(OpCodes.Conv_U4);
1727 else
1728 il.Emit(OpCodes.Conv_Ovf_U4);
1729 return;
1730 case TypeCode.Int64:
1731 return;
1732 case TypeCode.UInt64:
1733 if (truncationPermitted)
1734 il.Emit(OpCodes.Conv_U8);
1735 else
1736 il.Emit(OpCodes.Conv_Ovf_U8);
1737 return;
1738 case TypeCode.Single:
1739 case TypeCode.Double:
1740 il.Emit(OpCodes.Conv_R8);
1741 return;
1742 case TypeCode.Boolean:
1743 il.Emit(OpCodes.Ldc_I4_0);
1744 il.Emit(OpCodes.Conv_I8);
1745 il.Emit(OpCodes.Ceq);
1746 il.Emit(OpCodes.Ldc_I4_0);
1747 il.Emit(OpCodes.Ceq);
1748 return;
1749 case TypeCode.Decimal:
1750 il.Emit(OpCodes.Call, CompilerGlobals.int64ToDecimalMethod);
1751 return;
1752 case TypeCode.DateTime:
1753 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1754 return;
1755 case TypeCode.String:
1756 Convert.EmitLdloca(il, Typeob.Int64);
1757 il.Emit(OpCodes.Call, CompilerGlobals.int64ToStringMethod);
1758 return;
1760 break;
1762 case TypeCode.UInt64:
1763 switch (target){
1764 case TypeCode.Object:
1765 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1766 return;
1767 il.Emit(OpCodes.Box, source_type);
1768 Convert.Emit(ast, il, Typeob.Object, target_type);
1769 return;
1770 case TypeCode.SByte:
1771 if (truncationPermitted)
1772 il.Emit(OpCodes.Conv_I1);
1773 else
1774 il.Emit(OpCodes.Conv_Ovf_I1);
1775 return;
1776 case TypeCode.Byte:
1777 if (truncationPermitted)
1778 il.Emit(OpCodes.Conv_U1);
1779 else
1780 il.Emit(OpCodes.Conv_Ovf_U1);
1781 return;
1782 case TypeCode.Int16:
1783 if (truncationPermitted)
1784 il.Emit(OpCodes.Conv_I2);
1785 else
1786 il.Emit(OpCodes.Conv_Ovf_I2);
1787 return;
1788 case TypeCode.Char:
1789 case TypeCode.UInt16:
1790 if (truncationPermitted)
1791 il.Emit(OpCodes.Conv_U2);
1792 else
1793 il.Emit(OpCodes.Conv_Ovf_U2);
1794 return;
1795 case TypeCode.Int32:
1796 if (truncationPermitted)
1797 il.Emit(OpCodes.Conv_I4);
1798 else
1799 il.Emit(OpCodes.Conv_Ovf_I4);
1800 return;
1801 case TypeCode.UInt32:
1802 if (truncationPermitted)
1803 il.Emit(OpCodes.Conv_U4);
1804 else
1805 il.Emit(OpCodes.Conv_Ovf_U4);
1806 return;
1807 case TypeCode.Int64:
1808 if (truncationPermitted)
1809 il.Emit(OpCodes.Conv_I8);
1810 else
1811 il.Emit(OpCodes.Conv_Ovf_I8_Un);
1812 return;
1813 case TypeCode.UInt64:
1814 return;
1815 case TypeCode.Single:
1816 case TypeCode.Double:
1817 il.Emit(OpCodes.Conv_R_Un);
1818 return;
1819 case TypeCode.Boolean:
1820 il.Emit(OpCodes.Ldc_I4_0);
1821 il.Emit(OpCodes.Conv_I8);
1822 il.Emit(OpCodes.Ceq);
1823 il.Emit(OpCodes.Ldc_I4_0);
1824 il.Emit(OpCodes.Ceq);
1825 return;
1826 case TypeCode.Decimal:
1827 il.Emit(OpCodes.Call, CompilerGlobals.uint64ToDecimalMethod);
1828 return;
1829 case TypeCode.DateTime:
1830 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1831 return;
1832 case TypeCode.String:
1833 Convert.EmitLdloca(il, Typeob.UInt64);
1834 il.Emit(OpCodes.Call, CompilerGlobals.uint64ToStringMethod);
1835 return;
1837 break;
1839 case TypeCode.Single:
1840 switch (target){
1841 case TypeCode.Object:
1842 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1843 return;
1844 il.Emit(OpCodes.Box, source_type);
1845 Convert.Emit(ast, il, Typeob.Object, target_type);
1846 return;
1847 case TypeCode.SByte:
1848 if (truncationPermitted)
1849 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_I1);
1850 else{
1851 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1852 il.Emit(OpCodes.Conv_Ovf_I1);
1854 return;
1855 case TypeCode.Int16:
1856 if (truncationPermitted)
1857 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_I2);
1858 else{
1859 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1860 il.Emit(OpCodes.Conv_Ovf_I2);
1862 return;
1863 case TypeCode.Int32:
1864 if (truncationPermitted)
1865 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_I4);
1866 else{
1867 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1868 il.Emit(OpCodes.Conv_I4);
1870 return;
1871 case TypeCode.Byte:
1872 if (truncationPermitted)
1873 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_U1);
1874 else{
1875 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1876 il.Emit(OpCodes.Conv_Ovf_U1);
1878 return;
1879 case TypeCode.Char:
1880 case TypeCode.UInt16:
1881 if (truncationPermitted)
1882 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_U2);
1883 else{
1884 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1885 il.Emit(OpCodes.Conv_Ovf_U2);
1887 return;
1888 case TypeCode.UInt32:
1889 if (truncationPermitted)
1890 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_Ovf_U4);
1891 else{
1892 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1893 il.Emit(OpCodes.Conv_Ovf_U4);
1895 return;
1896 case TypeCode.Int64:
1897 if (truncationPermitted)
1898 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_I8);
1899 else{
1900 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1901 il.Emit(OpCodes.Conv_I8);
1903 return;
1904 case TypeCode.UInt64:
1905 if (truncationPermitted)
1906 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_U8);
1907 else{
1908 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1909 il.Emit(OpCodes.Conv_Ovf_U8);
1911 return;
1912 case TypeCode.Single:
1913 case TypeCode.Double:
1914 return;
1915 case TypeCode.DateTime:
1916 if (truncationPermitted)
1917 Convert.EmitSingleToIntegerTruncatedConversion(il, OpCodes.Conv_I8);
1918 else{
1919 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
1920 il.Emit(OpCodes.Conv_Ovf_I8);
1922 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
1923 return;
1924 case TypeCode.Boolean:
1925 case TypeCode.Decimal:
1926 case TypeCode.String:
1927 il.Emit(OpCodes.Conv_R8);
1928 Convert.Emit(ast, il, Typeob.Double, target_type);
1929 return;
1931 break;
1933 case TypeCode.Double:
1934 switch (target){
1935 case TypeCode.Object:
1936 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
1937 return;
1938 il.Emit(OpCodes.Box, source_type);
1939 Convert.Emit(ast, il, Typeob.Object, target_type);
1940 return;
1941 case TypeCode.SByte:
1942 if (truncationPermitted)
1943 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_I1);
1944 else{
1945 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1946 il.Emit(OpCodes.Conv_Ovf_I1);
1948 return;
1949 case TypeCode.Int16:
1950 if (truncationPermitted)
1951 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_I2);
1952 else{
1953 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1954 il.Emit(OpCodes.Conv_Ovf_I2);
1956 return;
1957 case TypeCode.Int32:
1958 if (truncationPermitted)
1959 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_I4);
1960 else{
1961 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1962 il.Emit(OpCodes.Conv_Ovf_I4);
1964 return;
1965 case TypeCode.Byte:
1966 if (truncationPermitted)
1967 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_U1);
1968 else{
1969 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1970 il.Emit(OpCodes.Conv_Ovf_U1);
1972 return;
1973 case TypeCode.Char:
1974 case TypeCode.UInt16:
1975 if (truncationPermitted)
1976 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_U2);
1977 else{
1978 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1979 il.Emit(OpCodes.Conv_Ovf_U2);
1981 return;
1982 case TypeCode.UInt32:
1983 if (truncationPermitted)
1984 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_U4);
1985 else{
1986 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1987 il.Emit(OpCodes.Conv_Ovf_U4);
1989 return;
1990 case TypeCode.Int64:
1991 if (truncationPermitted)
1992 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_I8);
1993 else{
1994 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
1995 il.Emit(OpCodes.Conv_I8);
1997 return;
1998 case TypeCode.UInt64:
1999 if (truncationPermitted)
2000 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_U8);
2001 else{
2002 il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
2003 il.Emit(OpCodes.Conv_Ovf_U8);
2005 return;
2006 case TypeCode.Single:
2007 case TypeCode.Double:
2008 return;
2009 case TypeCode.Boolean:
2010 il.Emit(OpCodes.Call, CompilerGlobals.doubleToBooleanMethod);
2011 return;
2012 case TypeCode.Decimal:
2013 il.Emit(OpCodes.Call, CompilerGlobals.doubleToDecimalMethod);
2014 return;
2015 case TypeCode.DateTime:
2016 if (truncationPermitted)
2017 Convert.EmitDoubleToIntegerTruncatedConversion(il, OpCodes.Conv_I8);
2018 else{
2019 il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
2020 il.Emit(OpCodes.Conv_Ovf_I8);
2022 il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
2023 return;
2024 case TypeCode.String:
2025 il.Emit(OpCodes.Call, CompilerGlobals.doubleToStringMethod);
2026 return;
2028 break;
2030 case TypeCode.Decimal:
2031 switch (target){
2032 case TypeCode.Object:
2033 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
2034 return;
2035 il.Emit(OpCodes.Box, source_type);
2036 Convert.Emit(ast, il, Typeob.Object, target_type);
2037 return;
2038 case TypeCode.Char:
2039 case TypeCode.SByte:
2040 case TypeCode.Byte:
2041 case TypeCode.Int16:
2042 case TypeCode.UInt16:
2043 case TypeCode.Int32:
2044 if (truncationPermitted){
2045 Convert.EmitDecimalToIntegerTruncatedConversion(il, OpCodes.Conv_I4);
2046 }else
2047 il.Emit(OpCodes.Call, CompilerGlobals.decimalToInt32Method);
2048 Convert.Emit(ast, il, Typeob.Int32, target_type, truncationPermitted);
2049 return;
2050 case TypeCode.UInt32:
2051 if (truncationPermitted){
2052 Convert.EmitDecimalToIntegerTruncatedConversion(il, OpCodes.Conv_U4);
2053 }else
2054 il.Emit(OpCodes.Call, CompilerGlobals.decimalToUInt32Method);
2055 return;
2056 case TypeCode.Boolean:
2057 il.Emit(OpCodes.Ldsfld, CompilerGlobals.decimalZeroField);
2058 il.Emit(OpCodes.Call, CompilerGlobals.decimalCompare);
2059 il.Emit(OpCodes.Ldc_I4_0);
2060 il.Emit(OpCodes.Ceq);
2061 il.Emit(OpCodes.Ldc_I4_0);
2062 il.Emit(OpCodes.Ceq);
2063 return;
2064 case TypeCode.Single:
2065 case TypeCode.Double:
2066 il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
2067 Convert.Emit(ast, il, Typeob.Double, target_type, truncationPermitted);
2068 return;
2069 case TypeCode.Int64:
2070 if (truncationPermitted){
2071 Convert.EmitDecimalToIntegerTruncatedConversion(il, OpCodes.Conv_I8);
2072 }else
2073 il.Emit(OpCodes.Call, CompilerGlobals.decimalToInt64Method);
2074 return;
2075 case TypeCode.UInt64:
2076 if (truncationPermitted){
2077 Convert.EmitDecimalToIntegerTruncatedConversion(il, OpCodes.Conv_U8);
2078 }else
2079 il.Emit(OpCodes.Call, CompilerGlobals.decimalToUInt64Method);
2080 return;
2081 case TypeCode.Decimal:
2082 return;
2083 case TypeCode.DateTime:
2084 if (truncationPermitted){
2085 Convert.EmitDecimalToIntegerTruncatedConversion(il, OpCodes.Conv_I8);
2086 }else
2087 il.Emit(OpCodes.Call, CompilerGlobals.decimalToInt64Method);
2088 Convert.Emit(ast, il, Typeob.Int64, target_type);
2089 return;
2090 case TypeCode.String:
2091 Convert.EmitLdloca(il, source_type);
2092 il.Emit(OpCodes.Call, CompilerGlobals.decimalToStringMethod);
2093 return;
2095 break;
2097 case TypeCode.DateTime:
2098 switch (target){
2099 case TypeCode.Object:
2100 if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
2101 return;
2102 il.Emit(OpCodes.Box, source_type);
2103 Convert.Emit(ast, il, Typeob.Object, target_type);
2104 return;
2105 case TypeCode.Boolean:
2106 case TypeCode.Char:
2107 case TypeCode.SByte:
2108 case TypeCode.Byte:
2109 case TypeCode.Int16:
2110 case TypeCode.UInt16:
2111 case TypeCode.Int32:
2112 case TypeCode.UInt32:
2113 case TypeCode.Int64:
2114 case TypeCode.UInt64:
2115 case TypeCode.Single:
2116 case TypeCode.Double:
2117 case TypeCode.Decimal:
2118 Convert.EmitLdloca(il, source_type);
2119 il.Emit(OpCodes.Call, CompilerGlobals.dateTimeToInt64Method);
2120 Convert.Emit(ast, il, Typeob.Int64, target_type, truncationPermitted);
2121 return;
2122 case TypeCode.DateTime:
2123 return;
2124 case TypeCode.String:
2125 Convert.EmitLdloca(il, source_type);
2126 il.Emit(OpCodes.Call, CompilerGlobals.dateTimeToStringMethod);
2127 return;
2129 break;
2131 case TypeCode.String:
2132 switch (target){
2133 case TypeCode.Object:
2134 if (target_type != Typeob.Object && !(target_type is TypeBuilder) && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
2135 return;
2136 Convert.Emit(ast, il, Typeob.Object, target_type);
2137 return;
2138 case TypeCode.Boolean:
2139 case TypeCode.Char:
2140 case TypeCode.SByte:
2141 case TypeCode.Byte:
2142 case TypeCode.Int16:
2143 case TypeCode.UInt16:
2144 case TypeCode.Int32:
2145 case TypeCode.UInt32:
2146 case TypeCode.Int64:
2147 case TypeCode.UInt64:
2148 case TypeCode.Single:
2149 case TypeCode.Double:
2150 case TypeCode.Decimal:
2151 case TypeCode.DateTime:
2152 //Resort to calling the Coerce routine. The extra call and the extra box/unbox adds neglible cost to such an expensive conversion.
2153 if (truncationPermitted && target == TypeCode.Int32){
2154 il.Emit(OpCodes.Call, CompilerGlobals.toInt32Method);
2155 return;
2156 }else{
2157 ConstantWrapper.TranslateToILInt(il, (int)target);
2158 ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
2159 il.Emit(OpCodes.Call, CompilerGlobals.coerce2Method);
2161 if (target_type.IsValueType) //Should always be true, but may as well check
2162 Convert.EmitUnbox(il, target_type, target);
2163 return;
2164 case TypeCode.String:
2165 return;
2167 break;
2169 Convert.Emit(ast, il, source_type, Typeob.Object); //The thing on the stack cannot be converted to target_type. Arrange for an error message.
2170 il.Emit(OpCodes.Call, CompilerGlobals.throwTypeMismatch);
2171 LocalBuilder tok = il.DeclareLocal(target_type); //Add dummy code to reassure the verifier.
2172 il.Emit(OpCodes.Ldloc, tok);
2175 // Emit code sequence used for explicit casts from floating point numbers to integer values.
2176 // A call is needed because the built in opcodes such as Conv.I4 have unspecified behavior
2177 // if the value overflows the integer.
2178 internal static void EmitSingleToIntegerTruncatedConversion(ILGenerator il, OpCode opConversion) {
2179 il.Emit(OpCodes.Conv_R8);
2180 EmitDoubleToIntegerTruncatedConversion(il, opConversion);
2182 internal static void EmitDoubleToIntegerTruncatedConversion(ILGenerator il, OpCode opConversion) {
2183 il.Emit(OpCodes.Call, CompilerGlobals.doubleToInt64);
2184 if (!opConversion.Equals(OpCodes.Conv_I8))
2185 il.Emit(opConversion);
2187 internal static void EmitDecimalToIntegerTruncatedConversion(ILGenerator il, OpCode opConversion) {
2188 il.Emit(OpCodes.Call, CompilerGlobals.uncheckedDecimalToInt64Method);
2189 if (!opConversion.Equals(OpCodes.Conv_I8))
2190 il.Emit(opConversion);
2193 internal static void EmitUnbox(ILGenerator il, Type target_type, TypeCode target){
2194 il.Emit(OpCodes.Unbox, target_type);
2195 switch(target){
2196 case TypeCode.Boolean:
2197 case TypeCode.Byte:
2198 il.Emit(OpCodes.Ldind_U1); return;
2199 case TypeCode.Char:
2200 case TypeCode.UInt16:
2201 il.Emit(OpCodes.Ldind_U2); return;
2202 case TypeCode.SByte:
2203 il.Emit(OpCodes.Ldind_I1); return;
2204 case TypeCode.Int16:
2205 il.Emit(OpCodes.Ldind_I2); return;
2206 case TypeCode.Int32:
2207 il.Emit(OpCodes.Ldind_I4); return;
2208 case TypeCode.UInt32:
2209 il.Emit(OpCodes.Ldind_U4); return;
2210 case TypeCode.Int64:
2211 case TypeCode.UInt64:
2212 il.Emit(OpCodes.Ldind_I8); return;
2213 case TypeCode.Single:
2214 il.Emit(OpCodes.Ldind_R4); return;
2215 case TypeCode.Double:
2216 il.Emit(OpCodes.Ldind_R8); return;
2217 default:
2218 il.Emit(OpCodes.Ldobj, target_type); return;
2222 private static bool EmittedCallToConversionMethod(AST ast, ILGenerator il, Type source_type, Type target_type){
2223 //Look for an explicit conversion, call that if there is one
2224 MethodInfo meth = target_type.GetMethod("op_Explicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
2225 if (meth != null){
2226 il.Emit(OpCodes.Call, meth);
2227 Convert.Emit(ast, il, meth.ReturnType, target_type);
2228 return true;
2230 meth = Convert.GetToXXXXMethod(source_type, target_type, true);
2231 if (meth != null){
2232 il.Emit(OpCodes.Call, meth);
2233 return true;
2236 //Look for implicit conversion, call that if there is one
2237 meth = target_type.GetMethod("op_Implicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
2238 if (meth != null){
2239 il.Emit(OpCodes.Call, meth);
2240 Convert.Emit(ast, il, meth.ReturnType, target_type);
2241 return true;
2243 meth = Convert.GetToXXXXMethod(source_type, target_type, false);
2244 if (meth != null){
2245 il.Emit(OpCodes.Call, meth);
2246 return true;
2248 return false;
2251 internal static void EmitLdarg(ILGenerator il, short argNum){
2252 switch(argNum){
2253 case 0 : il.Emit(OpCodes.Ldarg_0); return;
2254 case 1 : il.Emit(OpCodes.Ldarg_1); return;
2255 case 2 : il.Emit(OpCodes.Ldarg_2); return;
2256 case 3 : il.Emit(OpCodes.Ldarg_3); return;
2258 if (argNum < 256)
2259 il.Emit(OpCodes.Ldarg_S, (byte)argNum);
2260 else
2261 il.Emit(OpCodes.Ldarg, argNum);
2264 internal static void EmitLdloca(ILGenerator il, Type source_type){
2265 LocalBuilder tok = il.DeclareLocal(source_type);
2266 il.Emit(OpCodes.Stloc, tok);
2267 il.Emit(OpCodes.Ldloca, tok);
2270 private static IReflect GetArrayElementType(IReflect ir){
2271 if (ir is TypedArray)
2272 return ((TypedArray)ir).elementType;
2273 else if (ir is Type && ((Type)ir).IsArray)
2274 return ((Type)ir).GetElementType();
2275 else if (ir is ArrayObject || ir == Typeob.ArrayObject)
2276 return Typeob.Object;
2277 else
2278 return null;
2281 internal static int GetArrayRank(IReflect ir){
2282 if (ir == Typeob.ArrayObject || ir is ArrayObject)
2283 return 1;
2284 else if (ir is TypedArray)
2285 return ((TypedArray)ir).rank;
2286 else if (ir is Type && ((Type)ir).IsArray)
2287 return ((Type)ir).GetArrayRank();
2288 else
2289 return -1;
2292 internal static IConvertible GetIConvertible(Object ob){
2293 return ob as IConvertible;
2296 private static MethodInfo GetToXXXXMethod(IReflect ir, Type desiredType, bool explicitOK){
2297 if ((ir is TypeBuilder) || (ir is EnumBuilder)) return null;
2298 MemberInfo[] members = ir.GetMember(explicitOK ? "op_Explicit" : "op_Implicit", BindingFlags.Public|BindingFlags.Static);
2299 if (members != null)
2300 foreach(MemberInfo mem in members)
2301 if (mem is MethodInfo)
2302 if (((MethodInfo)mem).ReturnType == desiredType)
2303 return (MethodInfo)mem;
2304 return null;
2307 internal static TypeCode GetTypeCode(Object ob, IConvertible ic){
2308 if (ob == null) return TypeCode.Empty;
2309 if (ic == null) return TypeCode.Object;
2310 return ic.GetTypeCode();
2313 internal static TypeCode GetTypeCode(Object ob){
2314 return Convert.GetTypeCode(ob, Convert.GetIConvertible(ob));
2317 internal static Type GetUnderlyingType(Type type){
2318 if (type is TypeBuilder) return type.UnderlyingSystemType;
2319 return Enum.GetUnderlyingType(type);
2322 internal static bool IsArray(IReflect ir){
2323 return ir == Typeob.Array || ir == Typeob.ArrayObject || ir is TypedArray ||
2324 ir is ArrayObject || (ir is Type && ((Type)ir).IsArray);
2327 private static bool IsArrayElementTypeKnown(IReflect ir){
2328 Debug.PreCondition(IsArray(ir));
2329 return ir == Typeob.ArrayObject || ir is TypedArray ||
2330 ir is ArrayObject || (ir is Type && ((Type)ir).IsArray);
2333 internal static bool IsArrayRankKnown(IReflect ir) {
2334 Debug.PreCondition(IsArray(ir));
2335 return ir == Typeob.ArrayObject || ir is TypedArray ||
2336 ir is ArrayObject || (ir is Type && ((Type)ir).IsArray);
2339 internal static bool IsArrayType(IReflect ir){
2340 return ir is TypedArray || ir == Typeob.Array || ir == Typeob.ArrayObject || (ir is Type && ((Type)ir).IsArray);
2343 internal static bool IsJScriptArray(IReflect ir){
2344 return ir is ArrayObject || ir == Typeob.ArrayObject;
2347 internal static bool IsPrimitiveSignedNumericType(Type t){
2348 switch(Type.GetTypeCode(t)){
2349 case TypeCode.Single:
2350 case TypeCode.Double:
2351 case TypeCode.SByte:
2352 case TypeCode.Int16:
2353 case TypeCode.Int32:
2354 case TypeCode.Int64: return true;
2356 return false;
2359 internal static bool IsPrimitiveSignedIntegerType(Type t){
2360 switch(Type.GetTypeCode(t)){
2361 case TypeCode.SByte:
2362 case TypeCode.Int16:
2363 case TypeCode.Int32:
2364 case TypeCode.Int64: return true;
2366 return false;
2369 internal static bool IsPrimitiveUnsignedIntegerType(Type t){
2370 switch(Type.GetTypeCode(t)){
2371 case TypeCode.Byte:
2372 case TypeCode.UInt16:
2373 case TypeCode.UInt32:
2374 case TypeCode.UInt64: return true;
2376 return false;
2379 internal static bool IsPrimitiveIntegerType(Type t){
2380 switch(Type.GetTypeCode(t)){
2381 case TypeCode.SByte:
2382 case TypeCode.Byte:
2383 case TypeCode.Int16:
2384 case TypeCode.UInt16:
2385 case TypeCode.Int32:
2386 case TypeCode.UInt32:
2387 case TypeCode.Int64:
2388 case TypeCode.UInt64: return true;
2390 return false;
2393 internal static bool IsPrimitiveNumericTypeCode(TypeCode tc){
2394 switch(tc){
2395 case TypeCode.SByte:
2396 case TypeCode.Byte:
2397 case TypeCode.Int16:
2398 case TypeCode.UInt16:
2399 case TypeCode.Int32:
2400 case TypeCode.UInt32:
2401 case TypeCode.Int64:
2402 case TypeCode.UInt64:
2403 case TypeCode.Single:
2404 case TypeCode.Double: return true;
2406 return false;
2409 internal static bool IsPrimitiveNumericType(IReflect ir){
2410 Type t = ir as Type;
2411 if (t == null) return false;
2412 return Convert.IsPrimitiveNumericTypeCode(Type.GetTypeCode(t));
2415 internal static bool IsPrimitiveNumericTypeFitForDouble(IReflect ir){
2416 Type t = ir as Type;
2417 if (t == null) return false;
2418 switch (Type.GetTypeCode(t)){
2419 case TypeCode.SByte:
2420 case TypeCode.Byte:
2421 case TypeCode.Int16:
2422 case TypeCode.UInt16:
2423 case TypeCode.Int32:
2424 case TypeCode.UInt32:
2425 case TypeCode.Single:
2426 case TypeCode.Double: return true;
2428 return false;
2431 /* indicates whether all values of source type can be converted to the target type without loss of information */
2432 private static bool[,] promotable = new bool[,]
2433 { /*target type*/
2434 /*source Empty Object DBNull Boolean Char SByte Byte Int16 UInt16 Int32 UInt32 Int64 UInt64 Single Double Decimal DateTime TimeSpan String*/
2435 /*Empty*/ { true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
2436 /*Object*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
2437 /*DBNull*/ { true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
2438 /*Boolean*/ { false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false},
2439 /*Char*/ { false, false, false, false, true, false, false, false, true, true, true, true, true, true, true, true, true, true, false},
2440 /*SByte*/ { false, false, false, false, false, true, false, true, false, true, false, true, false, true, true, true, true, true, false},
2441 /*Byte*/ { false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, false},
2442 /*Int16*/ { false, false, false, false, false, true, false, true, false, true, false, true, false, true, true, true, true, true, false},
2443 /*UInt16*/ { false, false, false, false, true, false, false, false, true, true, true, true, true, true, true, true, true, true, false},
2444 /*Int32*/ { false, false, false, false, false, false, false, false, false, true, false, true, false, false, true, true, true, true, false},
2445 /*UInt32*/ { false, false, false, false, false, false, false, false, false, false, true, true, true, false, true, true, true, true, false},
2446 /*Int64*/ { false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false},
2447 /*UInt64*/ { false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, true, true, true, false},
2448 /*Single*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, false, false, false},
2449 /*Double*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false},
2450 /*Decimal*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false},
2451 /*DateTime*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false},
2452 /*TimeSpan*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false},
2453 /*String*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}
2455 // By "promotable" we mean that:
2456 // * value types may be promoted to other value types if there is no possible loss of data
2457 // (Int16 is promotable to Double, but Double is not promotable to Int16.)
2458 // * value types may be promoted to their wrapper reference types
2459 // (A boolean is promotable to a Boolean object.)
2460 // * reference types may be promoted to reference types they inherit from, but not vice-versa.
2461 // (A Derived is promotable to a Base, but a Base is not promotable to a Derived.)
2463 private static bool IsPromotableTo(Type source_type, Type target_type){
2464 TypeCode source = Type.GetTypeCode(source_type);
2465 TypeCode target = Type.GetTypeCode(target_type);
2466 if (Convert.promotable[(int)source, (int)target])
2467 return true;
2468 if ((source == TypeCode.Object || source == TypeCode.String) && target == TypeCode.Object){
2469 if (target_type.IsAssignableFrom(source_type))
2470 return true;
2471 if (target_type == Typeob.BooleanObject && source_type == Typeob.Boolean)
2472 return true;
2473 if (target_type == Typeob.StringObject && source_type == Typeob.String)
2474 return true;
2475 if (target_type == Typeob.NumberObject && Convert.IsPromotableTo(source_type, Typeob.Double))
2476 return true;
2477 if (target_type == Typeob.Array || source_type == Typeob.Array || target_type.IsArray || source_type.IsArray)
2478 return Convert.IsPromotableToArray(source_type, target_type);
2480 if (source_type == Typeob.BooleanObject && target_type == Typeob.Boolean)
2481 return true;
2482 if (source_type == Typeob.StringObject && target_type == Typeob.String)
2483 return true;
2484 if (source_type == Typeob.DateObject && target_type == Typeob.DateTime)
2485 return true;
2486 if (source_type == Typeob.NumberObject)
2487 return Convert.IsPrimitiveNumericType(target_type);
2488 if (source_type.IsEnum) return !target_type.IsEnum && Convert.IsPromotableTo(Convert.GetUnderlyingType(source_type), target_type);
2489 if (target_type.IsEnum) return !source_type.IsEnum && Convert.IsPromotableTo(source_type, Convert.GetUnderlyingType(target_type));
2490 //Look for implicit conversions.
2491 MethodInfo meth = target_type.GetMethod("op_Implicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
2492 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0) return true;
2493 meth = Convert.GetToXXXXMethod(source_type, target_type, false);
2494 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0) return true;
2495 return false;
2498 internal static bool IsPromotableTo(IReflect source_ir, IReflect target_ir){
2499 Type target_type;
2500 if (source_ir is TypedArray || target_ir is TypedArray ||
2501 source_ir is ArrayObject || target_ir is ArrayObject ||
2502 source_ir == Typeob.ArrayObject || target_ir == Typeob.ArrayObject)
2503 return Convert.IsPromotableToArray(source_ir, target_ir);
2504 if (target_ir is ClassScope){
2505 if (((ClassScope)target_ir).owner is EnumDeclaration){
2506 if (Convert.IsPrimitiveNumericType(source_ir))
2507 return IsPromotableTo(source_ir, ((EnumDeclaration)((ClassScope)target_ir).owner).baseType.ToType());
2508 else if (source_ir == Typeob.String) return true;
2509 else if (source_ir == target_ir) return true;
2510 return false;
2512 if (source_ir is ClassScope)
2513 return (((ClassScope)source_ir).IsSameOrDerivedFrom((ClassScope)target_ir));
2514 return false; //The source is not in the same compilation unit. Thus it can only extend the target type if there is a circular dependency and separate compilation. Can't handle that.
2515 }else if (target_ir is Type){
2516 if (target_ir == Typeob.Object) return !(source_ir is Type) || !((Type)source_ir).IsByRef;
2517 target_type = (Type)target_ir;
2518 }else if (target_ir is ScriptFunction)
2519 target_type = Typeob.ScriptFunction;
2520 else
2521 //assert that target_ir is JSObject
2522 target_type = Globals.TypeRefs.ToReferenceContext(target_ir.GetType());
2523 if (source_ir is ClassScope)
2524 return ((ClassScope)source_ir).IsPromotableTo(target_type);
2525 else
2526 return IsPromotableTo(source_ir is Type ? (Type)source_ir : Globals.TypeRefs.ToReferenceContext(source_ir.GetType()), target_type);
2529 // IsPromotableToArray determines whether or not we _know_ at compile time
2530 // that a given source type may be _promoted_ safely to a given target type.
2531 // Here we are concerned about two things:
2532 // (1) Is the target a base class of the source?
2533 // (2) Is the target a wrapper class of the source?
2535 // We wish to implement the following semantics:
2537 // * No non-array is promotable to any array.
2538 // * An array is only promotable to another array or Object.
2539 // * Any array (regardless of element type or rank) is promotable to Object.
2540 // * JScript arrays are not promotable to anything except JS Array and Object.
2541 // * Every array (other than JScript array) is promotable to System.Array.
2542 // * System.Array is not promotable to anything -- we do not have enough information
2543 // to make a safe promotion. Note that System Arrays are _assignment compatible_ to
2544 // JScript arrays but not _promotable_ to JScript arrays. We wish to be conservative
2545 // here and we do not know if the System.Array is of rank one.
2546 // * Any rank-one array (regardless of element type) is promotable to a JScript array
2547 // via the wrapper class.
2548 // * A source array is promotable to a typed array only if the source and the target
2549 // are known to be both equal in rank and element-type compatible.
2550 // * By "element type compatible" we mean the following: Value types are only compatible
2551 // with equal value types. (Int16[] is not promotable to Int32[] even though Int16
2552 // is promotable to Int32.) Value types are never compatible with reference types.
2553 // (Int32[] is not promotable to Object[].) Reference types are only compatible if
2554 // they are promotable. (Derived[] is promotable to Base[] but Base[] is not
2555 // promotable to Derived[].)
2557 private static bool IsPromotableToArray(IReflect source_ir, IReflect target_ir){
2558 Debug.PreCondition(IsArray(source_ir) || IsArray(target_ir));
2559 if (!IsArray(source_ir))
2560 return false;
2561 else if (target_ir == Typeob.Object)
2562 return true;
2563 else if (!IsArray(target_ir)){
2564 if (target_ir is Type){
2565 Type tt = (Type)target_ir;
2566 if (tt.IsInterface && tt.IsAssignableFrom(Typeob.Array))
2567 return source_ir is TypedArray || (source_ir is Type && ((Type)source_ir).IsArray);
2569 return false;
2570 }else if (IsJScriptArray(source_ir) && !IsJScriptArray(target_ir))
2571 return false;
2572 else if (target_ir == Typeob.Array)
2573 return !IsJScriptArray(source_ir);
2574 else if (source_ir == Typeob.Array)
2575 return false;
2576 else if (GetArrayRank(source_ir) == 1 && IsJScriptArray(target_ir))
2577 return true;
2578 else if (GetArrayRank(source_ir) != GetArrayRank(target_ir))
2579 return false;
2581 IReflect source_element_ir = GetArrayElementType(source_ir);
2582 IReflect target_element_ir = GetArrayElementType(target_ir);
2584 if (null == source_element_ir || null == target_element_ir)
2585 return false;
2587 if ((source_element_ir is Type && ((Type)source_element_ir).IsValueType) ||
2588 (target_element_ir is Type && ((Type)target_element_ir).IsValueType))
2589 return source_element_ir == target_element_ir;
2590 else
2591 return Convert.IsPromotableTo(source_element_ir, target_element_ir);
2594 private static bool IsWhiteSpace(char c) {
2595 switch (c) {
2596 case (char)0x09:
2597 case (char)0x0A:
2598 case (char)0x0B:
2599 case (char)0x0C:
2600 case (char)0x0D:
2601 case (char)0x20:
2602 case (char)0xA0:
2603 return true;
2604 default:
2605 if (c >= 128)
2606 return Char.IsWhiteSpace(c);
2607 else
2608 return false;
2612 private static bool IsWhiteSpaceTrailer(char[] s, int i, int max){
2613 for (; i < max; i++)
2614 if (!IsWhiteSpace(s[i])) return false;
2615 return true;
2618 internal static Object LiteralToNumber(String str){
2619 return Convert.LiteralToNumber(str, null);
2622 internal static Object LiteralToNumber(String str, Context context){
2623 //Called from the parser for integer literals
2624 uint r = 10;
2625 if (str[0] == '0' && str.Length > 1)
2626 if (str[1] == 'x' || str[1] == 'X')
2627 r = 16;
2628 else
2629 r = 8;
2630 Object result = Convert.parseRadix(str.ToCharArray(), r, r == 16 ? 2 : 0, 1, false);
2631 if (result != null){
2633 if (r == 8 && context != null && result is Int32 && ((int)result) > 7)
2634 context.HandleError(JSError.OctalLiteralsAreDeprecated);
2635 return result;
2637 context.HandleError(JSError.BadOctalLiteral);
2638 return Convert.parseRadix(str.ToCharArray(), 10, 0, 1, false);
2641 internal static bool NeedsWrapper(TypeCode code){
2642 switch (code){
2643 case TypeCode.Boolean:
2644 case TypeCode.Char:
2645 case TypeCode.SByte:
2646 case TypeCode.Byte:
2647 case TypeCode.Int16:
2648 case TypeCode.UInt16:
2649 case TypeCode.Int32:
2650 case TypeCode.UInt32:
2651 case TypeCode.Int64:
2652 case TypeCode.UInt64:
2653 case TypeCode.Single:
2654 case TypeCode.Double:
2655 case TypeCode.Decimal:
2656 case TypeCode.String: return true;
2658 return false;
2661 private static double DoubleParse(String str){
2662 try{
2663 return Double.Parse(str, NumberStyles.Float, CultureInfo.InvariantCulture);
2664 }catch(OverflowException){
2665 int i = 0; int n = str.Length;
2666 while (i < n && IsWhiteSpace(str[i])) i++;
2667 if (i < n && str[i] == '-')
2668 return Double.NegativeInfinity;
2669 else
2670 return Double.PositiveInfinity;
2674 private static Object parseRadix(char[] s, uint rdx, int i, int sign, bool ignoreTrailers){
2675 int max = s.Length;
2676 if (i >= max) return null;
2677 ulong multmax = (ulong)(UInt64.MaxValue / rdx);
2678 int digit = RadixDigit(s[i], rdx);
2679 if (digit < 0) return null;
2680 ulong result = (ulong)digit;
2681 int saved_i = i;
2682 for (;;){
2683 if (++i == max) goto returnAsInteger;
2684 digit = RadixDigit(s[i], rdx);
2685 if (digit < 0)
2686 if (ignoreTrailers || IsWhiteSpaceTrailer(s, i, max))
2687 goto returnAsInteger;
2688 else
2689 return null;
2690 if (result > multmax) goto returnAsDouble;
2691 unchecked{
2692 ulong r1 = result * rdx;
2693 ulong r2 = r1 + (ulong)digit;
2694 if (r1 > r2) goto returnAsDouble;
2695 result = r2;
2699 returnAsInteger:
2700 if (sign < 0){
2701 if (result <= 2147483648) return (int)(-(long)result);
2702 if (result < 9223372036854775808) return -(long)result;
2703 if (result == 9223372036854775808) return -9223372036854775808;
2704 return -(double)result;
2706 if (result <= 2147483647) return (int)result;
2707 if (result <= 9223372036854775807) return (long)result;
2708 return result;
2710 returnAsDouble:
2711 //too long for a ulong. Try double. Be consistent with Double.FromString.
2712 if (rdx == 10)
2713 try{
2714 double r = DoubleParse(new String(s, saved_i, max-saved_i));
2715 if (r == r) return sign*r;
2716 if (!ignoreTrailers) return null;
2717 }catch{}
2719 //Get here for string with trailers, or for radix other than 10
2720 //continue accummulating, but with loss of precision. Not quite as good as Double.FromString, but simple.
2721 double double_result = ((double)result)*rdx + digit;
2722 for (;;){
2723 if (++i == max) return sign*double_result;
2724 digit = RadixDigit(s[i], rdx);
2725 if (digit < 0)
2726 if (ignoreTrailers || IsWhiteSpaceTrailer(s, i, max))
2727 return sign*double_result;
2728 else
2729 return null;
2730 double_result = double_result*rdx + digit;
2734 private static int RadixDigit(char c, uint r){
2735 int d;
2736 if (c >= '0' && c <= '9')
2737 d = ((int)c) - ((int)'0');
2738 else if (c >= 'A' && c <= 'Z')
2739 d = 10 + ((int)c) - ((int)'A');
2740 else if (c >= 'a' && c <= 'z')
2741 d = 10 + ((int)c) - ((int)'a');
2742 else
2743 return -1;
2744 if (d >= r)
2745 return -1;
2746 else
2747 return d;
2750 #if !DEBUG
2751 [DebuggerStepThroughAttribute]
2752 [DebuggerHiddenAttribute]
2753 #endif
2754 public static void ThrowTypeMismatch(Object val){
2755 throw new JScriptException(JSError.TypeMismatch, new Context(new DocumentContext("", null), val.ToString()));
2758 public static bool ToBoolean(double d){
2759 return d == d && d != 0;
2762 #if !DEBUG
2763 [DebuggerStepThroughAttribute]
2764 [DebuggerHiddenAttribute]
2765 #endif
2766 public static bool ToBoolean(Object value){
2767 if (value is Boolean) return (bool)value;
2768 return Convert.ToBoolean(value, Convert.GetIConvertible(value));
2771 #if !DEBUG
2772 [DebuggerStepThroughAttribute]
2773 [DebuggerHiddenAttribute]
2774 #endif
2775 public static bool ToBoolean(Object value, bool explicitConversion){
2776 if (value is Boolean) return (bool)value;
2777 if (!explicitConversion && value is BooleanObject) return ((BooleanObject)value).value;
2778 return Convert.ToBoolean(value, Convert.GetIConvertible(value));
2781 #if !DEBUG
2782 [DebuggerStepThroughAttribute]
2783 [DebuggerHiddenAttribute]
2784 #endif
2785 internal static bool ToBoolean(Object value, IConvertible ic){
2786 switch (Convert.GetTypeCode(value, ic)){
2787 case TypeCode.Empty: return false;
2788 case TypeCode.Object:
2789 if (value is Missing || value is System.Reflection.Missing) return false;
2790 Type t = value.GetType();
2791 MethodInfo meth = t.GetMethod("op_True", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{t}, null);
2792 if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0 && meth.ReturnType == typeof(Boolean)){
2793 meth = new JSMethodInfo(meth);
2794 return (bool)meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
2796 return true;
2797 case TypeCode.DBNull: return false;
2798 case TypeCode.Boolean: return ic.ToBoolean(null);
2799 case TypeCode.Char: return ic.ToChar(null) != (Char)0;
2800 case TypeCode.SByte:
2801 case TypeCode.Byte:
2802 case TypeCode.Int16:
2803 case TypeCode.UInt16:
2804 case TypeCode.Int32: return ic.ToInt32(null) != 0;
2805 case TypeCode.UInt32:
2806 case TypeCode.Int64: return ic.ToInt64(null) != 0;
2807 case TypeCode.UInt64: return ic.ToUInt64(null) != 0;
2808 case TypeCode.Single:
2809 case TypeCode.Double:
2810 double d = ic.ToDouble(null);
2811 if (d != d) return false; else return d != 0;
2812 case TypeCode.Decimal: return ic.ToDecimal(null) != (Decimal)0;
2813 case TypeCode.DateTime: return true;
2814 case TypeCode.String: return ic.ToString(null).Length != 0;
2816 return false; //should never get here
2819 internal static char ToChar(Object value){
2820 return (char)Convert.ToUint32(value);
2823 private static char ToDigit(int digit) {
2824 return digit < 10 ? (char)('0' + digit) : (char)('a' + digit - 10);
2827 public static Object ToForInObject(Object value, VsaEngine engine){
2828 if (value is ScriptObject) return value;
2829 IConvertible ic = Convert.GetIConvertible(value);
2830 switch (Convert.GetTypeCode(value, ic)){
2831 case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructImplicitWrapper(ic.ToBoolean(null));
2832 case TypeCode.Char:
2833 case TypeCode.SByte:
2834 case TypeCode.Byte:
2835 case TypeCode.Int16:
2836 case TypeCode.UInt16:
2837 case TypeCode.Int32:
2838 case TypeCode.UInt32:
2839 case TypeCode.Int64:
2840 case TypeCode.UInt64:
2841 case TypeCode.Single:
2842 case TypeCode.Double:
2843 case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructImplicitWrapper(value);
2844 case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(ic.ToString(null));
2845 case TypeCode.DateTime: return value;
2846 case TypeCode.Object:
2847 return value;
2849 return engine.Globals.globalObject.originalObject.ConstructObject();
2852 internal static double ToInteger(double number) {
2853 if (number != number)
2854 return 0;
2855 return Math.Sign(number)*Math.Floor(Math.Abs(number));
2858 internal static double ToInteger(Object value){
2859 if (value is Double) return Convert.ToInteger((double)value);
2860 if (value is Int32) return (double)(int)value;
2861 return Convert.ToInteger(value, Convert.GetIConvertible(value));
2864 internal static double ToInteger(Object value, IConvertible ic){
2865 switch (Convert.GetTypeCode(value, ic)){
2866 case TypeCode.Empty: return 0;
2867 case TypeCode.DBNull: return 0;
2868 case TypeCode.Boolean: return ic.ToBoolean(null) ? 1 : 0;
2869 case TypeCode.Char: return (double)ic.ToChar(null);
2870 case TypeCode.SByte:
2871 case TypeCode.Byte:
2872 case TypeCode.Int16:
2873 case TypeCode.UInt16:
2874 case TypeCode.Int32:
2875 case TypeCode.UInt32:
2876 case TypeCode.Int64:
2877 case TypeCode.UInt64: return ic.ToDouble(null);
2878 case TypeCode.Single:
2879 case TypeCode.Double:
2880 case TypeCode.Decimal: return Convert.ToInteger(ic.ToDouble(null));
2881 case TypeCode.Object:
2882 case TypeCode.DateTime:
2883 Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
2884 if (pval != value)
2885 return Convert.ToInteger(Convert.ToNumber(pval, ic));
2886 else
2887 return Double.NaN;
2888 case TypeCode.String: return Convert.ToInteger(Convert.ToNumber(ic.ToString(null)));
2890 return 0; //should never get here
2893 public static int ToInt32(Object value){
2894 if (value is Double) return (int)Runtime.DoubleToInt64((double)value);
2895 if (value is Int32) return (int)value;
2896 return Convert.ToInt32(value, Convert.GetIConvertible(value));
2899 internal static int ToInt32(Object value, IConvertible ic){
2900 switch (Convert.GetTypeCode(value, ic)){
2901 case TypeCode.Empty: return 0;
2902 case TypeCode.DBNull: return 0;
2903 case TypeCode.Boolean: return ic.ToBoolean(null) ? 1 : 0;
2904 case TypeCode.Char: return (int)ic.ToChar(null);
2905 case TypeCode.SByte:
2906 case TypeCode.Byte:
2907 case TypeCode.Int16:
2908 case TypeCode.UInt16:
2909 case TypeCode.Int32: return ic.ToInt32(null);
2910 case TypeCode.UInt32:
2911 case TypeCode.Int64: return (int)ic.ToInt64(null);
2912 case TypeCode.UInt64: return (int)ic.ToUInt64(null);
2913 case TypeCode.Single:
2914 case TypeCode.Double: return (int)Runtime.DoubleToInt64(ic.ToDouble(null));
2915 case TypeCode.Decimal: return (int)Runtime.UncheckedDecimalToInt64(ic.ToDecimal(null));
2916 case TypeCode.Object:
2917 case TypeCode.DateTime:
2918 Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
2919 if (pval != value)
2920 return Convert.ToInt32(pval, ic);
2921 else
2922 return 0;
2923 case TypeCode.String: return (int)Runtime.DoubleToInt64(Convert.ToNumber(ic.ToString(null)));
2925 return 0; //should never get here.
2928 internal static IReflect ToIReflect(Type t, VsaEngine engine){
2929 GlobalObject glob = engine.Globals.globalObject;
2930 Object result = t;
2931 if (t == Typeob.ArrayObject)
2932 result = glob.originalArray.Construct();
2933 else if (t == Typeob.BooleanObject)
2934 result = glob.originalBoolean.Construct();
2935 else if (t == Typeob.DateObject)
2936 result = glob.originalDate.Construct(new Object[0]);
2937 else if (t == Typeob.EnumeratorObject)
2938 result = glob.originalEnumerator.Construct(new Object[0]);
2939 else if (t == Typeob.ErrorObject)
2940 result = glob.originalError.Construct(new Object[0]);
2941 else if (t == Typeob.EvalErrorObject)
2942 result = glob.originalEvalError.Construct(new Object[0]);
2943 else if (t == Typeob.JSObject)
2944 result = glob.originalObject.Construct(new Object[0]);
2945 else if (t == Typeob.NumberObject)
2946 result = glob.originalNumber.Construct();
2947 else if (t == Typeob.RangeErrorObject)
2948 result = glob.originalRangeError.Construct(new Object[0]);
2949 else if (t == Typeob.ReferenceErrorObject)
2950 result = glob.originalReferenceError.Construct(new Object[0]);
2951 else if (t == Typeob.RegExpObject)
2952 result = glob.originalRegExp.Construct(new Object[0]);
2953 else if (t == Typeob.ScriptFunction)
2954 result = FunctionPrototype.ob;
2955 else if (t == Typeob.StringObject)
2956 result = glob.originalString.Construct();
2957 else if (t == Typeob.SyntaxErrorObject)
2958 result = glob.originalSyntaxError.Construct(new Object[0]);
2959 else if (t == Typeob.TypeErrorObject)
2960 result = glob.originalTypeError.Construct(new Object[0]);
2961 else if (t == Typeob.URIErrorObject)
2962 result = glob.originalURIError.Construct(new Object[0]);
2963 else if (t == Typeob.VBArrayObject)
2964 result = glob.originalVBArray.Construct();
2965 else if (t == Typeob.ArgumentsObject)
2966 result = glob.originalObject.Construct(new Object[0]);
2967 return (IReflect)result;
2970 public static double ToNumber(Object value){
2971 if (value is Int32) return (double)(int)value;
2972 if (value is Double) return (double)value;
2973 return Convert.ToNumber(value, Convert.GetIConvertible(value));
2976 internal static double ToNumber(Object value, IConvertible ic){
2977 switch (Convert.GetTypeCode(value, ic)){
2978 case TypeCode.Empty: return Double.NaN;
2979 case TypeCode.DBNull: return 0;
2980 case TypeCode.Boolean: return ic.ToBoolean(null) ? 1 : 0;
2981 case TypeCode.Char: return (double)ic.ToChar(null);
2982 case TypeCode.SByte:
2983 case TypeCode.Byte:
2984 case TypeCode.Int16:
2985 case TypeCode.UInt16:
2986 case TypeCode.Int32: return (double)ic.ToInt32(null);
2987 case TypeCode.UInt32:
2988 case TypeCode.Int64: return (double)ic.ToInt64(null);
2989 case TypeCode.UInt64: return (double)ic.ToUInt64(null);
2990 case TypeCode.Single:
2991 case TypeCode.Double:
2992 case TypeCode.Decimal: return ic.ToDouble(null);
2993 case TypeCode.Object:
2994 case TypeCode.DateTime:
2995 Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
2996 if (pval != value)
2997 return Convert.ToNumber(pval, ic);
2998 else
2999 return Double.NaN;
3000 case TypeCode.String: return Convert.ToNumber(ic.ToString(null));
3002 return 0; //should never get here
3005 public static double ToNumber(String str){
3006 return Convert.ToNumber(str, true, false, Missing.Value);
3009 internal static double ToNumber(String str, bool hexOK, bool octalOK, Object radix){
3010 //Called from ToNumber, GlobalObject.parseFloat, GlobalObject.parseInt and from the parser for floating point literals
3011 //ToNumber, parseFloat and parseInt each have their own pecularities when it comes to leading whitespace, trailing characters, signs and hex/octal.
3012 //For ToNumber: hexOK = true, octalOK = false
3013 //For parseFloat: hexOK = false, octalOK = false
3014 //For parseInt: hexOK = true, octalOK = true and radix might be supplied,
3015 //For floating point literals: hexOK = false, octalOK = false
3017 if (!octalOK){ //only parseInt will set octalOK. Integers can always be converted without COM+ help
3018 try{
3019 double d = DoubleParse(str); //This should work (and be fastest) for the common case
3020 if (d != 0) return d;
3021 int i = 0, n = str.Length;
3022 while (i < n && IsWhiteSpace(str[i])) i++;
3023 if (i < n && str[i] == '-')
3024 return (double)(-0.0);
3025 else
3026 return (double)0;
3027 }catch{
3028 //We might get here if there are trailing characters in the string that should be ignored.
3029 //parseFloat ignores leading whitespace and any trailing characters which do not form part of a StrDecimalLiteral
3030 //ToNumber ignores leading and trailing whitespace, but not other trailing characters
3031 //We should never get here if called from the parser for a floating point literal (COM+ should always work for those).
3032 int n = str.Length;
3033 int j = n-1;
3034 int i = 0;
3035 //skip leading whitespace
3036 while (i < n && IsWhiteSpace(str[i])) i++;
3037 if (hexOK){ //The ToNumber case.
3038 //Double.FromString might have failed because of trailing whitespace, or because this is a hexadecimal literal.
3039 while (j >= i && IsWhiteSpace(str[j])) j--; //Strip any trailing whitespace
3040 if (i > j) //String empty or all whitespace
3041 return (double)0;
3042 if (j < n-1) //Had some trailing whitespace, try COM+ again
3043 return Convert.ToNumber(str.Substring(i, j-i+1), hexOK, octalOK, radix);
3044 //otherwise drop through and try to parse the number as a hex literal
3045 }else{ //The parseFloat case: all trailers are ignored. Prefix starting at i must match StrDecimalLiteral
3046 //Might be "Infinity"
3047 if (n-i >= 8 && String.CompareOrdinal(str, i, "Infinity", 0, 8) == 0)
3048 return Double.PositiveInfinity;
3049 else if (n-i >= 9 && String.CompareOrdinal(str, i, "-Infinity", 0, 8) == 0)
3050 return Double.NegativeInfinity;
3051 else if (n-i >= 9 && String.CompareOrdinal(str, i, "+Infinity", 0, 8) == 0)
3052 return Double.PositiveInfinity;
3053 //Reduce string length until last character is a decimal digit or '.'
3054 char ch;
3055 //If the last character is a digit there could be noise further upstream. First skip over trailing digits
3056 while (j >= i){
3057 ch = str[j];
3058 if (!JSScanner.IsDigit(ch)) break;
3059 j--;
3061 while (j >= i){
3062 ch = str[j];
3063 if (JSScanner.IsDigit(ch)) break;
3064 j--;
3066 if (j < n-1) //Had some trailing noise, try COM+ again
3067 return Convert.ToNumber(str.Substring(i, j-i+1), hexOK, octalOK, radix);
3068 //Whatever is left in str does not parse to a double, give up and return NaN.
3069 return Double.NaN;
3073 //if we get here, we are dealing with an integer, or we might be dealing with (+|-)Infinity
3074 //Never get here for parseFloat or floating point literals from the parser.
3075 //For parseInt Only the prefix matters. Trailing characters (those that can not form part of an integer literal) are ignored.
3076 //For ToNumber, any trailing characters must be whitespace.
3078 int n = str.Length;
3079 int i = 0;
3080 //skip leading whitespace
3081 while (i < n && IsWhiteSpace(str[i])) i++;
3082 if (i >= n)
3083 if (hexOK && octalOK)
3084 return double.NaN; //parseInt case
3085 else
3086 return (double)0; //ToNumber case
3087 int sign = 1;
3088 bool explicitSign = false;
3089 if (str[i] == '-'){
3090 sign = -1; i++; explicitSign = true;
3091 }else if (str[i] == '+'){
3092 i++; explicitSign = true;
3094 while (i < n && IsWhiteSpace(str[i])) i++;
3095 bool radixMissing = radix == null || radix is Missing;
3096 if (i+8 <= n && radixMissing && !octalOK && str.Substring(i, 8).Equals("Infinity"))
3097 return sign > 0 ? Double.PositiveInfinity : Double.NegativeInfinity;
3098 int r = 10;
3099 if (!radixMissing)
3100 r = Convert.ToInt32(radix);
3101 if (r == 0){
3102 radixMissing = true;
3103 r = 10;
3104 }else if (r < 2 || r > 36)
3105 return Double.NaN;
3106 if (i < n-2 && str[i] == '0')
3107 if (str[i+1] == 'x' || str[i+1] == 'X'){
3108 if (!hexOK)
3109 return 0;
3110 if (explicitSign && !octalOK) //ToNumber case
3111 return Double.NaN;
3112 if (radixMissing){
3113 r = 16; i += 2;
3114 }else if (r == 16)
3115 i += 2;
3116 }else if (octalOK && radixMissing)
3117 r = 8;
3118 if (i < n)
3119 return Convert.ToNumber(Convert.parseRadix(str.ToCharArray(), (uint)r, i, sign, hexOK && octalOK));
3120 else
3121 return Double.NaN;
3125 internal static String ToLocaleString(Object value){
3126 return Convert.ToString(value, PreferredType.LocaleString, true);
3129 public static Object ToNativeArray(Object value, RuntimeTypeHandle handle){
3130 if (value is ArrayObject){
3131 Type elementType = Type.GetTypeFromHandle(handle);
3132 return ((ArrayObject)value).ToNativeArray(elementType);
3134 return value;
3137 public static Object ToObject(Object value, VsaEngine engine){
3138 if (value is ScriptObject) return value;
3139 String str = value as String;
3140 if (str != null) return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(str);
3141 IConvertible ic = Convert.GetIConvertible(value);
3142 switch (Convert.GetTypeCode(value, ic)){
3143 case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructImplicitWrapper(ic.ToBoolean(null));
3144 case TypeCode.Char:
3145 case TypeCode.SByte:
3146 case TypeCode.Byte:
3147 case TypeCode.Int16:
3148 case TypeCode.UInt16:
3149 case TypeCode.Int32:
3150 case TypeCode.UInt32:
3151 case TypeCode.Int64:
3152 case TypeCode.UInt64:
3153 case TypeCode.Single:
3154 case TypeCode.Double:
3155 case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructImplicitWrapper(value);
3156 case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(ic.ToString(null));
3157 case TypeCode.DateTime: return ic.ToDateTime(null);
3158 case TypeCode.Object:
3159 if (value is Array)
3160 return engine.Globals.globalObject.originalArray.ConstructImplicitWrapper((Array)value);
3161 else
3162 return value;
3164 throw new JScriptException(JSError.NeedObject);
3167 public static Object ToObject2(Object value, VsaEngine engine){
3168 if (value is ScriptObject) return value;
3169 IConvertible ic = Convert.GetIConvertible(value);
3170 switch (Convert.GetTypeCode(value, ic)){
3171 case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructImplicitWrapper(ic.ToBoolean(null));
3172 case TypeCode.Char:
3173 case TypeCode.SByte:
3174 case TypeCode.Byte:
3175 case TypeCode.Int16:
3176 case TypeCode.UInt16:
3177 case TypeCode.Int32:
3178 case TypeCode.UInt32:
3179 case TypeCode.Int64:
3180 case TypeCode.UInt64:
3181 case TypeCode.Single:
3182 case TypeCode.Double:
3183 case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructImplicitWrapper(value);
3184 case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(ic.ToString(null));
3185 case TypeCode.DateTime: return ic.ToDateTime(null);
3186 case TypeCode.Object:
3187 if (value is Array)
3188 return engine.Globals.globalObject.originalArray.ConstructImplicitWrapper((Array)value);
3189 else
3190 return value;
3192 return null;
3195 internal static Object ToObject3(Object value, VsaEngine engine){
3196 if (value is ScriptObject) return value;
3197 IConvertible ic = Convert.GetIConvertible(value);
3198 switch (Convert.GetTypeCode(value, ic)){
3199 case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructWrapper(ic.ToBoolean(null));
3200 case TypeCode.Char:
3201 case TypeCode.SByte:
3202 case TypeCode.Byte:
3203 case TypeCode.Int16:
3204 case TypeCode.UInt16:
3205 case TypeCode.Int32:
3206 case TypeCode.UInt32:
3207 case TypeCode.Int64:
3208 case TypeCode.UInt64:
3209 case TypeCode.Single:
3210 case TypeCode.Double:
3211 case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructWrapper(value);
3212 case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructWrapper(ic.ToString(null));
3213 case TypeCode.DateTime: return ic.ToDateTime(null);
3214 case TypeCode.Object:
3215 if (value is Array)
3216 return engine.Globals.globalObject.originalArray.ConstructWrapper((Array)value);
3217 else
3218 return value;
3220 return null;
3223 #if !DEBUG
3224 [DebuggerStepThroughAttribute]
3225 [DebuggerHiddenAttribute]
3226 #endif
3227 internal static Object ToPrimitive(Object value, PreferredType preferredType){
3228 IConvertible ic = Convert.GetIConvertible(value);
3229 TypeCode tcode = Convert.GetTypeCode(value, ic);
3230 return Convert.ToPrimitive(value, preferredType, ic, tcode);
3233 #if !DEBUG
3234 [DebuggerStepThroughAttribute]
3235 [DebuggerHiddenAttribute]
3236 #endif
3237 internal static Object ToPrimitive(Object value, PreferredType preferredType, ref IConvertible ic){
3238 TypeCode tcode = Convert.GetTypeCode(value, ic);
3239 switch (tcode){
3240 case TypeCode.Object:
3241 case TypeCode.DateTime:
3242 Object result = Convert.ToPrimitive(value, preferredType, ic, tcode);
3243 if (result != value){
3244 value = result;
3245 ic = Convert.GetIConvertible(value);
3247 break;
3249 return value;
3253 #if !DEBUG
3254 [DebuggerStepThroughAttribute]
3255 [DebuggerHiddenAttribute]
3256 #endif
3257 private static Object ToPrimitive(Object value, PreferredType preferredType, IConvertible ic, TypeCode tcode){
3258 switch (tcode){
3259 case TypeCode.Object:
3260 System.Array arr = value as System.Array;
3261 if (arr != null && arr.Rank == 1) value = new ArrayWrapper(ArrayPrototype.ob, arr, true);
3262 if (value is ScriptObject){
3263 Object result = ((ScriptObject)value).GetDefaultValue(preferredType);
3264 if (Convert.GetTypeCode(result) != TypeCode.Object)
3265 return result;
3266 else if (value == result && preferredType == PreferredType.String || preferredType == PreferredType.LocaleString){
3267 if (value is JSObject){
3268 ScriptObject proto = ((JSObject)value).GetParent();
3269 if (proto is ClassScope)
3270 return ((ClassScope)proto).GetFullName();
3271 return "[object Object]";
3273 return value.ToString();
3274 }else
3275 throw new JScriptException(JSError.TypeMismatch);
3276 }else if (value is Missing || value is System.Reflection.Missing)
3277 return null;
3278 else{
3279 IReflect ir;
3280 if (value is IReflect && !(value is Type))
3281 ir = (IReflect)value;
3282 else
3283 ir = value.GetType();
3285 //Look for an op_Explicit conversion to String or Double (this always fails for IDispatch/Ex objects
3286 MethodInfo meth = null;
3287 if (preferredType == PreferredType.String || preferredType == PreferredType.LocaleString)
3288 meth = Convert.GetToXXXXMethod(ir, typeof(String), true);
3289 else{
3290 meth = Convert.GetToXXXXMethod(ir, typeof(Double), true);
3291 if (meth == null)
3292 meth = Convert.GetToXXXXMethod(ir, typeof(Int64), true);
3293 if (meth == null)
3294 meth = Convert.GetToXXXXMethod(ir, typeof(UInt64), true);
3296 if (meth != null){
3297 meth = new JSMethodInfo(meth);
3298 return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
3301 //Invoke the default method/property or get the value of the default field. If an exception is thrown
3302 //because the target doesn't have a non-paramterized default member, mask it and execute the
3303 //default handling.
3304 try{
3305 try{
3306 MemberInfo member = LateBinding.SelectMember(JSBinder.GetDefaultMembers(Runtime.TypeRefs, ir));
3307 if (member != null){
3308 switch(member.MemberType){
3309 case MemberTypes.Field: return ((FieldInfo)member).GetValue(value);
3310 case MemberTypes.Method: return ((MethodInfo)member).Invoke(value, new Object[0]);
3311 case MemberTypes.Property: return JSProperty.GetValue((PropertyInfo)member, value, null);
3312 case MemberTypes.Event: return null;
3313 case MemberTypes.NestedType: return member;
3317 return ir.InvokeMember(String.Empty, BindingFlags.ExactBinding|BindingFlags.SuppressChangeType|
3318 BindingFlags.InvokeMethod|BindingFlags.GetProperty|BindingFlags.GetField,
3319 null, value, new Object[0], null, null, new String[0]);
3320 }catch(TargetInvocationException e){
3321 throw e.InnerException;
3323 }catch(ArgumentException){
3324 }catch(IndexOutOfRangeException){
3325 }catch(MissingMemberException){
3326 }catch(SecurityException){
3327 }catch(TargetParameterCountException){
3330 if (preferredType != PreferredType.Number)
3331 if (value is Char[])
3332 return new System.String((Char[])value);
3333 else
3334 return value.ToString();
3335 return value;
3337 case TypeCode.DateTime:
3338 return DateConstructor.ob.Construct(ic.ToDateTime(null)).GetDefaultValue(preferredType);
3340 return value;
3343 internal static String ToString(Object value){
3344 return Convert.ToString(value, PreferredType.String, true);
3347 #if !DEBUG
3348 [DebuggerStepThroughAttribute]
3349 [DebuggerHiddenAttribute]
3350 #endif
3351 public static String ToString(Object value, bool explicitOK){
3352 return Convert.ToString(value, PreferredType.String, explicitOK);
3355 #if !DEBUG
3356 [DebuggerStepThroughAttribute]
3357 [DebuggerHiddenAttribute]
3358 #endif
3359 internal static String ToString(Object value, IConvertible ic){
3360 return Convert.ToString(value, PreferredType.String, ic, true);
3363 #if !DEBUG
3364 [DebuggerStepThroughAttribute]
3365 [DebuggerHiddenAttribute]
3366 #endif
3367 internal static String ToString(Object value, PreferredType pref, bool explicitOK){
3368 String str = value as String;
3369 if (str != null) return str;
3370 StringObject strObj = value as StringObject;
3371 if (strObj != null && strObj.noExpando) return strObj.value;
3372 return Convert.ToString(value, pref, Convert.GetIConvertible(value), explicitOK);
3375 #if !DEBUG
3376 [DebuggerStepThroughAttribute]
3377 [DebuggerHiddenAttribute]
3378 #endif
3379 internal static String ToString(Object value, PreferredType pref, IConvertible ic, bool explicitOK){
3380 Enum e = value as Enum;
3381 if (e != null) return e.ToString("G");
3382 EnumWrapper ew = value as EnumWrapper;
3383 if (ew != null) return ew.ToString();
3384 TypeCode code = Convert.GetTypeCode(value, ic);
3385 if (pref == PreferredType.LocaleString){
3386 switch (code){
3387 case TypeCode.SByte:
3388 case TypeCode.Byte:
3389 case TypeCode.Int16:
3390 case TypeCode.UInt16:
3391 case TypeCode.Int32:
3392 case TypeCode.UInt32:
3393 case TypeCode.Single:
3394 case TypeCode.Double: {
3395 double d = ic.ToDouble(null);
3396 return d.ToString(d <= -1e+15 || d >= 1e+15 ? "g" : "n", NumberFormatInfo.CurrentInfo);
3398 case TypeCode.Int64: return ic.ToInt64(null).ToString("n", NumberFormatInfo.CurrentInfo);
3399 case TypeCode.UInt64: return ic.ToUInt64(null).ToString("n", NumberFormatInfo.CurrentInfo);
3400 case TypeCode.Decimal: return ic.ToDecimal(null).ToString("n", NumberFormatInfo.CurrentInfo);
3403 switch (code){
3404 case TypeCode.Empty: return explicitOK ? "undefined" : null;
3405 case TypeCode.Object: return Convert.ToString(Convert.ToPrimitive(value, pref, ref ic), ic);
3406 case TypeCode.DBNull: return explicitOK ? "null" : null;
3407 case TypeCode.Boolean: return ic.ToBoolean(null) ? "true" : "false";
3408 case TypeCode.Char:
3409 case TypeCode.SByte:
3410 case TypeCode.Byte:
3411 case TypeCode.Int16:
3412 case TypeCode.UInt16:
3413 case TypeCode.Int32:
3414 case TypeCode.UInt32:
3415 case TypeCode.Int64:
3416 case TypeCode.UInt64:
3417 case TypeCode.Decimal:
3418 case TypeCode.String: return ic.ToString(null);
3419 case TypeCode.DateTime: return Convert.ToString(DateConstructor.ob.Construct(ic.ToDateTime(null)));
3420 case TypeCode.Single:
3421 case TypeCode.Double: return Convert.ToString(ic.ToDouble(null));
3423 return null; //Should never get here
3426 public static String ToString(bool b){
3427 return b ? "true" : "false";
3430 public static String ToString(double d){
3431 long i = (long)d;
3432 if ((double)i == d){
3433 return i.ToString(CultureInfo.InvariantCulture);
3434 }else if (d != d)
3435 return "NaN";
3436 else if (Double.IsPositiveInfinity(d))
3437 return "Infinity";
3438 else if (Double.IsNegativeInfinity(d))
3439 return "-Infinity";
3440 else{
3441 double e = d < 0 ? -d : d;
3442 int k = 15;
3443 String result = e.ToString("e14", CultureInfo.InvariantCulture);
3444 if (DoubleParse(result) != e){
3445 result = e.ToString("e15", CultureInfo.InvariantCulture);
3446 k = 16;
3447 if (DoubleParse(result) != e){
3448 result = e.ToString("e16", CultureInfo.InvariantCulture);
3449 k = 17;
3450 if (DoubleParse(result) != e){
3451 result = e.ToString("e17", CultureInfo.InvariantCulture);
3452 k = 18;
3456 int exp = Int32.Parse(result.Substring(k+2, result.Length-(k+2)), CultureInfo.InvariantCulture);
3457 while (result[k] == '0') k--; //at the end of the loop, k == the number of significant digits
3458 int n = exp + 1;
3459 if (k <= n && n <= 21){
3460 StringBuilder r = new StringBuilder(n+1);
3461 if (d < 0)
3462 r.Append('-');
3463 r.Append(result[0]);
3464 if (k > 1)
3465 r.Append(result, 2, k-1);
3466 if (exp-k >= 0)
3467 r.Append('0', n-k);
3468 return r.ToString();
3470 if (0 < n && n <= 21){
3471 StringBuilder r = new StringBuilder(k+2);
3472 if (d < 0)
3473 r.Append('-');
3474 r.Append(result[0]);
3475 if (n > 1)
3476 r.Append(result, 2, n-1);
3477 r.Append('.');
3478 r.Append(result, n+1, k-n);
3479 return r.ToString();
3481 if (-6 < n && n <= 0){
3482 StringBuilder r = new StringBuilder(2-n);
3483 if (d < 0)
3484 r.Append("-0.");
3485 else
3486 r.Append("0.");
3487 if (n < 0)
3488 r.Append('0', -n);
3489 r.Append(result[0]);
3490 r.Append(result, 2, k-1);
3491 return r.ToString();
3494 StringBuilder r = new StringBuilder(28);
3495 if (d < 0)
3496 r.Append('-');
3497 r.Append(result.Substring(0, k == 1 ? 1 : k+1));
3498 r.Append('e');
3499 if (exp >= 0)
3500 r.Append('+');
3501 r.Append(exp);
3502 return r.ToString();
3507 private static int[] rgcchSig = new int[] {
3508 53, 34, 27, 24, 22, 20, 19, 18, 17, 17, 16, 16,
3509 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13,
3510 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 };
3512 internal static String ToString(Object value, int radix) {
3513 if (radix == 10 || radix < 2 || radix > 36)
3514 return Convert.ToString(value);
3515 double dbl = Convert.ToNumber(value);
3516 if (dbl == 0.0)
3517 return "0";
3518 if (Double.IsNaN(dbl))
3519 return "NaN";
3520 if (Double.IsPositiveInfinity(dbl))
3521 return "Infinity";
3522 if (Double.IsNegativeInfinity(dbl))
3523 return "-Infinity";
3525 StringBuilder sb = new StringBuilder();
3526 if (dbl < 0.0) {
3527 sb.Append('-');
3528 dbl = -dbl;
3530 int cchMax = rgcchSig[radix - 2];
3532 if (dbl < 8.67361737988403547206e-19 || dbl >= 2305843009213693952.0) {
3533 // Exponential notation
3535 int wExp = (int)Math.Log(dbl, radix) + 1;
3536 double dblT = Math.Pow(radix, wExp);
3537 if (Double.IsPositiveInfinity(dblT))
3538 dblT = Math.Pow(radix, --wExp);
3539 else if (dblT == 0.0)
3540 dblT = Math.Pow(radix, ++wExp);
3541 dbl /= dblT;
3542 while (dbl < 1.0) {
3543 dbl *= radix;
3544 wExp--;
3547 int wDig = (int)dbl;
3548 sb.Append(Convert.ToDigit(wDig));
3549 cchMax--;
3550 dbl -= wDig;
3552 if (dbl != 0.0) {
3553 sb.Append('.');
3554 while (dbl != 0.0 && cchMax-- > 0) {
3555 dbl *= radix;
3556 wDig = (int)dbl;
3557 if (wDig >= radix)
3558 wDig = radix - 1;
3559 sb.Append(Convert.ToDigit(wDig));
3560 dbl -= wDig;
3564 sb.Append((wExp >= 0 ? "(e+" : "(e"));
3565 sb.Append(wExp.ToString(CultureInfo.InvariantCulture));
3566 sb.Append(')');
3568 } else {
3569 // Regular notation
3571 int wDig, cchSig;
3572 if (dbl >= 1.0) {
3573 // Integral portion
3575 double dblDen, dblT;
3576 cchSig = 1;
3577 for (dblDen = 1.0; (dblT = dblDen * radix) <= dbl; dblDen = dblT)
3578 cchSig++;
3580 for (int cch = 0; cch < cchSig; cch++) {
3581 wDig = (int)(dbl / dblDen);
3582 if (wDig >= radix)
3583 wDig = radix - 1;
3584 sb.Append(Convert.ToDigit(wDig));
3585 dbl -= wDig * dblDen;
3586 dblDen /= radix;
3588 } else {
3589 sb.Append('0');
3590 cchSig = 0;
3593 if (dbl != 0.0 && cchSig < cchMax) {
3594 // Fractional portion
3596 sb.Append('.');
3597 while (dbl != 0.0 && cchSig < cchMax) {
3598 dbl *= radix;
3599 wDig = (int)dbl;
3600 if (wDig >= radix)
3601 wDig = radix - 1;
3602 sb.Append(Convert.ToDigit(wDig));
3603 dbl -= wDig;
3604 if (wDig != 0 || cchSig != 0)
3605 cchSig++;
3610 return sb.ToString();
3613 internal static Type ToType(IReflect ir){
3614 return Convert.ToType(Globals.TypeRefs, ir);
3617 internal static Type ToType(TypeReferences typeRefs, IReflect ir){
3618 if (ir is Type)
3619 return (Type)ir;
3620 if (ir is ClassScope)
3621 return ((ClassScope)ir).GetTypeBuilderOrEnumBuilder();
3622 if (ir is TypedArray){
3623 return typeRefs.ToReferenceContext(((TypedArray)ir).ToType());
3625 if (ir is ScriptFunction)
3626 return typeRefs.ScriptFunction;
3627 return typeRefs.ToReferenceContext(ir.GetType());
3630 internal static Type ToType(String descriptor, Type elementType){
3631 Module mod = elementType.Module;
3632 if (mod is ModuleBuilder)
3633 return mod.GetType(elementType.FullName+descriptor);
3634 else
3635 return mod.Assembly.GetType(elementType.FullName+descriptor);
3638 internal static String ToTypeName(IReflect ir){
3639 if (ir is ClassScope)
3640 return ((ClassScope)ir).GetName();
3641 else if (ir is JSObject)
3642 return ((JSObject)ir).GetClassName();
3643 else if (ir is GlobalScope)
3644 return "Global Object";
3645 else{
3646 Debug.Assert(ir is Type || ir is TypedArray);
3647 return ir.ToString();
3651 internal static uint ToUint32(Object value){
3652 if (value is UInt32) return (uint)value;
3653 return Convert.ToUint32(value, Convert.GetIConvertible(value));
3656 internal static uint ToUint32(Object value, IConvertible ic){
3657 switch (Convert.GetTypeCode(value, ic)){
3658 case TypeCode.Empty: return 0;
3659 case TypeCode.DBNull: return 0;
3660 case TypeCode.Boolean: return ic.ToBoolean(null) ? (uint)1 : (uint)0;
3661 case TypeCode.Char: return (uint)ic.ToChar(null);
3662 case TypeCode.Byte:
3663 case TypeCode.UInt16:
3664 case TypeCode.UInt32: return ic.ToUInt32(null);
3665 case TypeCode.UInt64: return (uint)ic.ToUInt64(null);
3666 case TypeCode.SByte:
3667 case TypeCode.Int16:
3668 case TypeCode.Int32:
3669 case TypeCode.Int64: return (uint)ic.ToInt64(null);
3670 case TypeCode.Single:
3671 case TypeCode.Double: return (uint)Runtime.DoubleToInt64(ic.ToDouble(null));
3672 case TypeCode.Decimal: return (uint)Runtime.UncheckedDecimalToInt64(ic.ToDecimal(null));
3673 case TypeCode.Object:
3674 case TypeCode.DateTime:
3675 Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
3676 if (pval != value)
3677 return Convert.ToUint32(pval, ic);
3678 else
3679 return 0;
3680 case TypeCode.String: return (uint)Runtime.DoubleToInt64(Convert.ToNumber(ic.ToString(null)));
3682 return 0; //should never get here